Dynamic API call

Тема в разделе "WASM.BEGINNERS", создана пользователем Aoizora, 29 янв 2017.

  1. Aoizora

    Aoizora Active Member

    Публикаций:
    0
    Регистрация:
    29 янв 2017
    Сообщения:
    362
    Хочу написать свою процедуру для динамического вызова API. Для этого я формирую шеллкод, который пушит аргументы вызываемой функции на стек, копирует в eax адрес функции и делает вызов call eax. Шеллкод формируется правильно, но при выполнении call eax ничего не происходит. С чем это связано? Когда я делаю то же самое в ассемблерной вставке внутри main(), вызов функции успешен, но когда я пытаюсь выполнить сформированный шеллкод при помощи CallWindowProc, CreateThread или просто __asm call shelcode, результата нет. В чем здесь проблема?

    Код (Text):
    1.  
    2. #include <windows.h>
    3. #include <stdio.h>
    4.  
    5. #pragma comment(lib, "user32.lib")
    6.  
    7. #define BEEP 0x8ca07e28
    8.  
    9. __declspec(naked) unsigned int GetKernel32(void)
    10. {
    11.    __asm
    12.    {
    13.      mov eax, fs:[0x30];     /* Get pointer to PEB */
    14.      mov eax, [eax + 0xC];   /* Get pointer to PEB_LDR_DATA */
    15.      mov eax, [eax + 0x14];   /* InMemoryOrderModuleList */
    16.  
    17.      mov eax, [eax];       /* Get the 2-nd entry */
    18.      mov eax, [eax];       /* Get the 3-rd entry */
    19.      mov eax, [eax + 0x10];   /* Get the 3-rd entry base address */
    20.  
    21.      ret;
    22.    };
    23. }
    24.  
    25. /*DWORD Hash(char *name)
    26. {
    27.    DWORD h = 0x74D8;
    28.    while (*name++)
    29.      h ^= (h << 7) + *name;
    30.    return h;
    31. }*/
    32.  
    33. unsigned int Hash(char* str)
    34. {
    35.   unsigned int hash = 0x01b63a;
    36.  
    37.   for(; *str; str++)
    38.   {
    39.   hash = ((hash << 5) + hash) + (*str);
    40.   }
    41.   return hash;  
    42. }
    43.  
    44. DWORD GetAPI(const DWORD library, const DWORD APIHASH)
    45. {
    46.    if (library)
    47.    {
    48.      PIMAGE_DOS_HEADER dos_hdr = (PIMAGE_DOS_HEADER)library;
    49.      PIMAGE_NT_HEADERS nt_hdr = (PIMAGE_NT_HEADERS)(library + dos_hdr->e_lfanew);
    50.      PIMAGE_OPTIONAL_HEADER optional_hdr = &nt_hdr->OptionalHeader;
    51.      PIMAGE_DATA_DIRECTORY data_directory = optional_hdr->DataDirectory;
    52.      PIMAGE_EXPORT_DIRECTORY export = (PIMAGE_EXPORT_DIRECTORY)(library + data_directory[0].VirtualAddress);
    53.  
    54.      DWORD *names = (DWORD *)(library + export->AddressOfNames);
    55.      WORD *ordinals = (WORD *)(library + export->AddressOfNameOrdinals);
    56.      DWORD *functions = (DWORD *)(library + export->AddressOfFunctions);
    57.  
    58.      for (int i = 0; i < export->NumberOfNames; ++i)
    59.      {
    60.        char *name = (char *)(library + names[i]);
    61.        if (Hash(name) == APIHASH)
    62.          return functions[ordinals[i]] + (DWORD)library;
    63.      }
    64.    }
    65. }
    66.  
    67. DWORD CallAPI(DWORD dwHash, DWORD nArgs, ...)
    68. {
    69.    va_list arg_list;
    70.    char *shellcode = VirtualAlloc(NULL, 40, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    71.  
    72.    va_start(arg_list, nArgs);
    73.  
    74.    /* push arguments from right to left */
    75.    for (int i = nArgs - 1; i >= 0; --i)
    76.    {
    77.      shellcode[5 * i] = 0x68;   /* opcode of push*/
    78.      shellcode[5 * i + 1] = va_arg(arg_list, DWORD);   /* what to push */
    79.    }
    80.  
    81.    va_end(arg_list);
    82.  
    83.    *(WORD  *)   &shellcode[5 * nArgs] = 0xB8;   /* mov eax, value */
    84.    *(DWORD *)   &shellcode[5 * nArgs + 1] = GetAPI(GetKernel32(), dwHash);
    85.    *(WORD  *)   &shellcode[5 * nArgs + 5] = 0xD0FF;   /* call eax */
    86.    *(WORD  *)   &shellcode[5 * nArgs + 7] = 0xC3;   /* ret */
    87.  
    88.    __asm call shellcode;
    89.    //CallWindowProc((WNDPROC)shellcode, 0, 0, 0, 0);
    90.  
    91.    //HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)shellcode, NULL, 0, 0);
    92.    //WaitForSingleObject(hThread, INFINITE);
    93.  
    94.    return 0;
    95. }
    96.  
    97.  
    98. typedef BOOL (WINAPI * noimport_beep) (DWORD, DWORD);
    99.  
    100. #define dwBeep 0xfa2c2f56
    101.  
    102. int main(int argc, char *argv[])
    103. {
    104.    __asm
    105.    {
    106.      push dwBeep;
    107.      call GetKernel32;
    108.      push eax;
    109.      call GetAPI;
    110.      push 700;
    111.      push 700;
    112.      call eax;
    113.      mov eax, 0x12345678;
    114.    };
    115.  
    116.    CallAPI(dwBeep, 2, 700, 700);
    117.  
    118.    //noimport_beep beep = (noimport_beep)GetAPI(GetKernel32(), dwBeep);
    119.    //beep(700, 1400);
    120. }
     
  2. yashechka

    yashechka Ростовский фанат Нарвахи

    Публикаций:
    90
    Регистрация:
    2 янв 2012
    Сообщения:
    1.449
    Адрес:
    Россия
    А Вы отладчиком не прогоняли, как я понял?
     
  3. Aoizora

    Aoizora Active Member

    Публикаций:
    0
    Регистрация:
    29 янв 2017
    Сообщения:
    362
    Выполнял шеллкод в олли, но не понял, почему произошло небольшое зависание на call eax и почему нет результата. Я же формирую шеллкод точно так же, как в ассемблерной вставке в main. Что могло пойти не так?
     
  4. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    887
    Во-первых, ошибка:
    Код (Text):
    1. shellcode[5 * i + 1] = va_arg(arg_list, DWORD)
    Тебе нужно писать DWORD, а ты пишешь char.
    Второй момент - кто будет следить за стеком? В ассемблерной вставке в функции main ты при вызове GetAPI нарушаешь структуру стека. Либо делай GetAPI __stdcall функцией либо добавляй к esp.
     
    Verc0tti и Aoizora нравится это.
  5. Aoizora

    Aoizora Active Member

    Публикаций:
    0
    Регистрация:
    29 янв 2017
    Сообщения:
    362
    Спасибо, проблема в самом деле была в размере записываемых данных.
    Как лучше вызывать этот шеллкод, чтобы из функции можно было вернуть, например, адрес выделенной памяти, если динамически была вызвана VirtualAlloc? __asm call shellcode должно ведь хватить, потому что возвращаемое значение тогда окажется в eax, а эпилог функции CallAPI никак не помешает

    PS. Проверил сам.
     
    Последнее редактирование: 29 янв 2017
  6. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    887
    Я бы сделал так:
    Код (C):
    1. void* (*p)(void) = (void*(*)(void))shellcode;
    2. return p();
    Сам тип функции тоже бы поменял на void*. Исключение асма облегчит переход на x64.