Как найти в памяти адрес конкретной инструкции в DLL

Как я могу найти в памяти адрес (для написания эксплойта) конкретной инструкции?

В частности, я ищу call ebp инструкция в user32.dll в Windows XP без пакета обновления, адрес которого я могу указать EIP к. У меня есть и Immunity Debugger, и OllyDBG, установленные на цели.

2 ответа

Решение

Чтобы найти инструкцию, вам нужно выяснить, где код, .text, раздел начинается и заканчивается, затем загружать DLL и просто выполнять поиск лайнера, пока не найдете инструкцию.

Здесь у нас есть тестовая DLL, которая имеет два call ebp инструкции:

// test.c
// gcc -Wall -shared test.c -o test.dll
#include <stdio.h>

__declspec(dllexport) void test(void) {
    asm("call *%ebp");
    puts("test");
    asm("call *%ebp");
}

Скомпилируйте его и загрузите DLL в ollydbg, нажмите CTRL+F и найдите CALL EBP:

6BEC125A  |. FFD5            CALL EBP
6BEC125C  |. C70424 6430EC6> MOV DWORD PTR SS:[ESP],test.6BEC3064 ; |ASCII "test"
6BEC1263  |. E8 74060000     CALL <JMP.&msvcrt.puts>              ; \puts
6BEC1268  |. FFD5            CALL EBP

Вы видите адрес первой инструкции по адресу 0x6bec125a второй в 0x6bec1268, Код операции call ebp является 0xff 0xd5запомни это.

Теперь нам нужно найти границы кода, вы можете использовать objdump с -h:

> objdump --headers test.dll

test.dll:     file format pei-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000984  6bec1000  6bec1000  00000600  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE, DATA

  1 .data         00000008  6bec2000  6bec2000  00001000  2**2
                  CONTENTS, ALLOC, LOAD, DATA

  2 .rdata        0000011c  6bec3000  6bec3000  00001200  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  ....

>

код начинается с VMA, адрес виртуальной памяти, 0x6bec1000 и его размер 0x984так что это заканчивается в 0x6bec1000 + 0x984 знак равно 0x6bec1984 как:

0x6bec1000
....
what is between are the DLL instructions
....
0x6bec1984

Я надеюсь, что это было ясно до сих пор.

Если мы хотим закодировать наш call ebp сканер, нам нужно сделать текущий:

  1. Прочитайте информацию PE и получите информацию об исполняемом разделе, обычно .text, чтобы найти его относительный адрес и его виртуальный размер.
  2. Загрузите DLL, используя LoadLibrary, она вернет базовый адрес DLL.
  3. Виртуальный адрес начала секции кода: Базовый адрес DLL + секция кода virtualAddress, и он заканчивается в Базовом адресе DLL + секция кода virtualAddress + VirtualSize.
  4. Теперь мы готовы пройтись по коду и искать 0xff 0xd5, call ebpкод операции, простой поиск лайнера.

Вот простая реализация:

// findopcode.c
// gcc -Wall findopcode.c -o findopcode

#include <windows.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv) {
    const char opcode[] = {0xff, 0xd5}; // The opcode of `call ebp'
    FILE *dllFile;
    HMODULE dllHandle;

    IMAGE_DOS_HEADER dosHeader;
    IMAGE_NT_HEADERS NtHeaders;
    IMAGE_SECTION_HEADER sectionHeader;

    unsigned int i;
    unsigned char *starAddr;
    unsigned char *endAddr;

    if( argc < 2 ) {
        printf("usage: %s [DLL]\n", argv[0]);
        return -1;
    }

    if( ( dllFile = fopen(argv[1], "rb") ) == NULL ) {
        perror("[!] Error");
        return -1;
    }

    // Read the basic PE headers
    fread(&dosHeader, sizeof(dosHeader), 1, dllFile);
    fseek(dllFile, dosHeader.e_lfanew, SEEK_SET);
    fread(&NtHeaders, sizeof(NtHeaders), 1, dllFile);

    // Search for the executable section, .text section.
    for( i = 0 ; i < NtHeaders.FileHeader.NumberOfSections ; i++ ) {
        fread(&sectionHeader, sizeof(sectionHeader), 1, dllFile);
        // If we found a section that contains executable code,
        // we found our code setion.
        if( (sectionHeader.Characteristics & IMAGE_SCN_CNT_CODE) != 0 ) {
            printf("[*] Code section: `%s'\n", sectionHeader.Name);
            break;
        }
    }

    fclose(dllFile);

    // Load the DLL to get it's base address
    if( (dllHandle = LoadLibraryA(argv[1])) == NULL ) {
        printf("[!] Error: loading the DLL, 0x%.8x\n", (unsigned int) GetLastError());
        return -1;
    }

    // The code start at : base address + code virtual address
    starAddr = (unsigned char *) dllHandle + sectionHeader.VirtualAddress;
    // It ends at : base address + code virtual address + virtual size
    endAddr = (unsigned char *) starAddr + sectionHeader.Misc.VirtualSize;

    printf("[*] Base address : 0x%.8x\n", (unsigned int) dllHandle);
    printf("[*] Start address: 0x%.8x\n", (unsigned int) starAddr);
    printf("[*] End address  : 0x%.8x\n", (unsigned int) endAddr);

    // Simple liner search, when ever we find `0xff 0xd5' we print that address
    for( endAddr -= sizeof(opcode) ; starAddr < endAddr ; starAddr++ ) {
        if( memcmp(&opcode, (void *) starAddr, sizeof(opcode)) == 0 ) {
            printf("[*] Found `call ebp` at: 0x%.8x\n", (unsigned int) starAddr);
        }
    }

    FreeLibrary(dllHandle);
    return 0;
}

Скомпилируйте и протестируйте эту DLL:

> gcc -Wall findopcode.c -o findopcode
> findopcode.exe test.dll
[*] Code section: `.text'
[*] Base address : 0x6bec0000
[*] Start address: 0x6bec1000
[*] End address  : 0x6bec1984
[*] Found `call ebp` at: 0x6bec125a
[*] Found `call ebp` at: 0x6bec1268

>

Это работает довольно хорошо, давайте попробуем user32.dll:

> findopcode.exe \Windows\System32\user32.dll
[*] Code section: `.text'
[*] Base address : 0x75680000
[*] Start address: 0x75681000
[*] End address  : 0x756e86ef
[*] Found `call ebp` at: 0x756b49b5

> 

Я нашел только один call ebp в 0x756b49b5, Обратите внимание, вы хотите проверить, есть ли у вас доступ для чтения, прежде чем читать с memcmp используя IsBadReadPtr:

        if( IsBadReadPtr(starAddr, sizeof(opcode)) == 0 &&
            memcmp(&opcode, (void *) starAddr, sizeof(opcode)) == 0 ) {

так что программа не выйдет из строя, если вы попадете в какую-то область со странным доступом.

Альтернативным способом является использование msfpescan из структуры Metasploit:

msfpescan -j ebp user32.dll
Другие вопросы по тегам