Как найти адрес в dll

Armin05

26.04.2012, 14:32

3

Цитата
Сообщение от Mikant
Посмотреть сообщение

какой DLL? какой игры? о чём вообще речь? перефразируй вопрос: что конкретно нужно, для чего, и что уже имеется…

игра Айон
речь идет о том какими командами вычислить базовый адрес dll игры.
в автоитие это реализовано следующим кодом

Код

Func _MemoryModuleGetBaseAddress($iPID, $sModule)
    If Not ProcessExists($iPID) Then Return SetError(1, 0, 0)

    If Not IsString($sModule) Then Return SetError(2, 0, 0)

    Local $PSAPI = DllOpen("psapi.dll")

    ;Get Process Handle
    Local $hProcess
    Local $PERMISSION = BitOR(0x0002, 0x0400, 0x0008, 0x0010, 0x0020) ; CREATE_THREAD, QUERY_INFORMATION, VM_OPERATION, VM_READ, VM_WRITE

    If $iPID > 0 Then
        Local $hProcess = DllCall("kernel32.dll", "ptr", "OpenProcess", "dword", $PERMISSION, "int", 0, "dword", $iPID)
        If $hProcess[0] Then
            $hProcess = $hProcess[0]
        EndIf
    EndIf

    ;EnumProcessModules
    Local $Modules = DllStructCreate("ptr[1024]")
    Local $aCall = DllCall($PSAPI, "int", "EnumProcessModules", "ptr", $hProcess, "ptr", DllStructGetPtr($Modules), "dword", DllStructGetSize($Modules), "dword*", 0)
    If $aCall[4] > 0 Then
        Local $iModnum = $aCall[4] / 4
        Local $aTemp
        For $i = 1 To $iModnum
            $aTemp = DllCall($PSAPI, "dword", "GetModuleBaseNameW", "ptr", $hProcess, "ptr", Ptr(DllStructGetData($Modules, 1, $i)), "wstr", "", "dword", 260)
            If $aTemp[3] = $sModule Then
                DllClose($PSAPI)
                Return Ptr(DllStructGetData($Modules, 1, $i))
            EndIf
        Next
    EndIf

    DllClose($PSAPI)
    Return SetError(-1, 0, 0)

EndFunc   ;==>_MemoryModuleGetBaseAddress

А как это реализовать в C# ????
помогите плиз

To find an instruction, you need to figure out where the code, .text, section starts and ends, then load the DLL and just do liner search until you find the instruction.

Here we have a test DLL that has two call ebp instructions:

// 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");
}

Compile it and load the DLL in ollydbg and click CTRL+F and search for 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

you see the address of the first instruction is at 0x6bec125a the second at 0x6bec1268. The opcode of call ebp is 0xff 0xd5, remember this.

Now we need to find the boundaries of the code, you can use objdump with -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
  ....

>

the code starts at VMA, virtual memory address, 0x6bec1000 and its size is 0x984, so it ends at 0x6bec1000 + 0x984 = 0x6bec1984 as :

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

I hope that was clear so far.

If we want to code our call ebp scanner, we need to do the flowing:

  1. Read the PE information and get the executable section information, usually .text, to find its relative address and its virtual size.
  2. Load the DLL using LoadLibrary, it will return the base address of the DLL.
  3. The virtual address of the beginning of the code section is: DLL base address + code section virtualAddress and it ends at DLL base address + code section virtualAddress + VirtualSize.
  4. Now we are ready to loop through the code and look for 0xff 0xd5, call ebp‘s opcode, simple liner search.

Here is a simple implementation:

// 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%.8xn", (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%.8xn", (unsigned int) dllHandle);
    printf("[*] Start address: 0x%.8xn", (unsigned int) starAddr);
    printf("[*] End address  : 0x%.8xn", (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%.8xn", (unsigned int) starAddr);
        }
    }

    FreeLibrary(dllHandle);
    return 0;
}

Compile it and test it with that 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

>

It works pretty well, let’s try user32.dll:

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

> 

I only found one call ebp at 0x756b49b5. Note, you way want to check if you have a read access before you read with memcmp using IsBadReadPtr:

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

so the program won’t fail if you hit some area with some weird access.

server.dll — Это адрес загруженного модуля, т.е. HMODULE/HINSTNACE или же просто void*.

GetModuleHandle вернет вам адрес загруженного модуля если он уже загружен.

То что у вас идет после server.dll, это отступ от адреса модуля, что бы узнать этот адрес, вам необходимо применить арифметику к указателю на начальный адрес модуля, в вашем случае прибавить к данному адресу значение 0066CAA (имейте ввиду, это число представлено в виде hex а полный адрес будет выглядеть так: 0x0066CAA = 421034).

В итоге имеем следующий код:

HMODULE server_module = GetModuleHandle("server.dll");
char* address_with_offset = ((char*)server_module) + 0x0066CAA;

Недавно я запустил новый консольный проект на C ++ win32.
Это в основном переписывает значение данного адреса в памяти.

Дело в том, что я хочу использовать карту указателей со смещениями, чтобы пересчитать адрес, который он должен использовать.
Вот изображение карты указателя в Cheat Engine

Как я уже сказал, мне удалось переписать значение (в данном случае 1147) вручную, если я просто наберу адрес, но я хочу, чтобы оно было автоматическим!
Надеюсь, вы понимаете мою проблему

хорошего дня.

0

Решение

Чтобы получить базовый адрес модуля (DLL или EXE) в памяти, вы можете перечислить загруженные модули, используя ToolHelp32Snapshot Функция Windows API. Microsoft предоставляет документированный исходный код для поиска модуля. В основном вам нужны 2 функции, одна для захвата ProcessId и одна для получения базового адреса.

bool GetPid(const wchar_t* targetProcess, DWORD* procID)
{
HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snap && snap != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32 pe;
pe.dwSize = sizeof(pe);
if (Process32First(snap, &pe))
{
do
{
if (!wcscmp(pe.szExeFile, targetProcess))
{
CloseHandle(snap);
*procID = pe.th32ProcessID;
return true;
}
} while (Process32Next(snap, &pe));
}
}
return false;
}

char* GetModuleBase(const wchar_t* ModuleName, DWORD procID)
{
MODULEENTRY32 ModuleEntry = { 0 };
HANDLE SnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procID);

if (!SnapShot) return NULL;

ModuleEntry.dwSize = sizeof(ModuleEntry);

if (!Module32First(SnapShot, &ModuleEntry)) return NULL;

do
{
if (!wcscmp(ModuleEntry.szModule, ModuleName))
{
CloseHandle(SnapShot);
return (char*)ModuleEntry.modBaseAddr;
}
} while (Module32Next(SnapShot, &ModuleEntry));

CloseHandle(SnapShot);
return NULL;
}

Тогда вы делаете:

DWORD ProcId;
GetPid(L"ac_client.exe", &ProcId);
char* ExeBaseAddress = GetModuleBase(L"ac_client.exe", ProcId);

Если вы внедрили этот процесс во внутренний хак, вы можете использовать GetModuleHandle потому что на момент публикации возвращаемый дескриптор является просто адресом модуля:

 DWORD BaseAddress = (DWORD)GetModuleHandle(L"ac_client.exe");

Чтобы вычислить динамический адрес, на который указывает многоуровневый указатель, вы можете использовать эту функцию, она в основном отменяет указатель на внешнюю ссылку для вас, используя ReadProcessMemory ():

uintptr_t FindDmaAddy(int PointerLevel, HANDLE hProcHandle, uintptr_t Offsets[], uintptr_t BaseAddress)
{
uintptr_t pointer = BaseAddress;
uintptr_t pTemp;

uintptr_t pointerAddr;
for(int i = 0; i < PointerLevel; i++)
{
if(i == 0)
{
ReadProcessMemory(hProcHandle, (LPCVOID)pointer, &pTemp, sizeof(pTemp), NULL);
}
pointerAddr = pTemp + Offsets[i];

ReadProcessMemory(hProcHandle, (LPCVOID)pointerAddr, &pTemp, sizeof(pTemp), NULL);
}
return pointerAddr;
}

1

Другие решения

Других решений пока нет …


  1. vovka

    vovka

    New Member

    Публикаций:

    0

    Регистрация:
    23 май 2006
    Сообщения:
    45

    как найти адрес DllMain в Dll файле?

    импорт разобрал, экспорт тоже а вот саму DllMain немогу

    найти как её искать:)

    AddressOfEntryPoint не то

    Спасибо


  2. vovka

    vovka

    New Member

    Публикаций:

    0

    Регистрация:
    23 май 2006
    Сообщения:
    45

    google на Рустэм PE Dll ничего не дал

    как его найти

    всё что я мог найти я прочитал, но найти DllMain не могу!


  3. vovka

    vovka

    New Member

    Публикаций:

    0

    Регистрация:
    23 май 2006
    Сообщения:
    45

    ??

    Я серьёзно!

    Я все заголовки разобрал, но ни в AddressOfEntryPoint ни

    в DLLCharachteristics нет

    дайте ссылку

    или ткните куда копать

    Спасибо!


  4. reverser

    reverser

    New Member

    Публикаций:

    0

    Регистрация:
    27 янв 2004
    Сообщения:
    615


  5. green

    green

    New Member

    Публикаций:

    0

    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine

    А на чём DLL написана? AddressOfEntryPoint может быть адресом ф-ции RTL, которя уже вызывает твою DllMain.

    Так, для VC это DllMainCRTStartup.

    Кстати DLL может и вовсе не иметь точки входа.

    Типичный случай – resource only dll.


  6. vovka

    vovka

    New Member

    Публикаций:

    0

    Регистрация:
    23 май 2006
    Сообщения:
    45

    Написал я свою маленькую DLL, вернее создал в VS2003!

    Только Одна DllMain!

    Когда делаю LoadLibrary! все ок!

    т.е. DLL правильная!

    Но найти аддресс DllMain не могу!


  7. P_F

    P_F

    New Member

    Публикаций:

    0

    Регистрация:
    27 мар 2006
    Сообщения:
    116
    Адрес:
    Russia

    google на Рустэм PE Dll ничего не дал

    как его найти

    Рустэм == Roustem

    Dll in binary [Roustem] ==Roustem – Dll в машинных кодах.

  8. 2 Roustem:

    Слава богу ты не видел этого поста во вторник утром :)))

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


  9. P_F

    P_F

    New Member

    Публикаций:

    0

    Регистрация:
    27 мар 2006
    Сообщения:
    116
    Адрес:
    Russia

    2 EvilsInterrupt:

    2 Roustem:???

    2 vovka:

    А нафига вообще тебе DLL Main если не секрет? А то может можно и проще…

    Кстати не знаю на сколько поможет Roustem, а вот на васме точно где то были очень хорошие доки по PE для exe и dll.


  10. P_F

    P_F

    New Member

    Публикаций:

    0

    Регистрация:
    27 мар 2006
    Сообщения:
    116
    Адрес:
    Russia

    Вот неплохая дока:

    (Документация по PE-файлам).zipCLR spec.doc


  11. crypto

    crypto

    Active Member

    Публикаций:

    0

    Регистрация:
    13 дек 2005
    Сообщения:
    2.533

    EvilsInterrupt

    Поздравляю с защитой. Какоя тема диплома?


  12. vovka

    vovka

    New Member

    Публикаций:

    0

    Регистрация:
    23 май 2006
    Сообщения:
    45

    P_F

    Вот разобрал весь DLL, а вот как найти DllMain не знаю!

    Я смотрю вопрос тяжёлый, т.к. никто внятно не ответил, да и в доках я ничего не нашёл! Но ведь такого не может быть!!!


  13. leo

    leo

    Active Member

    Публикаций:

    0

    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia

    vovka

    Тебе green уже ответил.

    Если ты пишешь dll “ручками” на асме (или в кодах а ля Roustem), то твоя DllMain – “настоящая” и располагается по AddressOfEntryPoint

    А вот во всяких ЯВУ добрые дяди из MS, Borland и т.п. пишут настоящую навороченную DllMain сами, а твоя DllMain – это лишь дополнительная пользовательская функция, которая вызывается из главной функции, автоматически создаваемой компилятором. Поэтому где находится именно твоя функция – зависит от компилятора. Поставь в начало int3 и посмотри в отладчике


  14. vovka

    vovka

    New Member

    Публикаций:

    0

    Регистрация:
    23 май 2006
    Сообщения:
    45

    leo

    я в отладчике видел!! Но найти не мог!

    Так всё-таки есть какие-то идеи как её найти, т.е.

    мою DllMain? Я в VS2003! Но ничего про этот механизм не сдышал!?

    и всё-таки!


  15. vovka

    vovka

    New Member

    Публикаций:

    0

    Регистрация:
    23 май 2006
    Сообщения:
    45

    leo

    кстати в ida открывал свою dll, там явно и красиво

    показано где начинается код DllMain!!!

    прямо ужас какой-то!


  16. leo

    leo

    Active Member

    Публикаций:

    0

    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia

    vovka

    > “явно и красиво показано где начинается код DllMain!!!”

    Ну и где же он “начинается” ?

    В загруженном образе адресу DllMain негде быть кроме как в ImageBase+AddressOfEntryPoint. Вот только ImageBase ес-но может не соответствовать значению в PE-заголовке, т.к. dll м.б. загружена по другому базовому адресу.

    Ну а в файле соответсвенно AddressOfEntryPoint – code.VirtualAddress + code.PointerToRawData

    Это касается адреса “настоящей” DllMain с точки зрения винды. А чего там ЯВУ-компиляторы могут замутить это другой вопрос. Например дельфи использует свою DllMain, в которой при DLL_PROCESS_ATTACH выполняет инициализию всех юнитов (секции initialization), а юзверю вместо виндового прототипа DllMain предлагает использовать свой прототип DllProc с единственным параметром Reason. Соответсвенно эта DllProc вызывается откуда-то из недр основной DllMain


WASM

Добавить комментарий