Armin05 |
|
26.04.2012, 14:32 |
3 |
какой 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:
- Read the PE information and get the executable section information, usually
.text
, to find its relative address and its virtual size. - Load the DLL using LoadLibrary, it will return the base address of the DLL.
- 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.
- 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(§ionHeader, 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
Другие решения
Других решений пока нет …
-
vovka
New Member
- Публикаций:
-
0
- Регистрация:
- 23 май 2006
- Сообщения:
- 45
как найти адрес DllMain в Dll файле?
импорт разобрал, экспорт тоже а вот саму DllMain немогу
найти как её искать
AddressOfEntryPoint не то
Спасибо
-
vovka
New Member
- Публикаций:
-
0
- Регистрация:
- 23 май 2006
- Сообщения:
- 45
google на Рустэм PE Dll ничего не дал
как его найти
всё что я мог найти я прочитал, но найти DllMain не могу!
-
vovka
New Member
- Публикаций:
-
0
- Регистрация:
- 23 май 2006
- Сообщения:
- 45
??
Я серьёзно!
Я все заголовки разобрал, но ни в AddressOfEntryPoint ни
в DLLCharachteristics нет
дайте ссылку
или ткните куда копать
Спасибо!
-
reverser
New Member
- Публикаций:
-
0
- Регистрация:
- 27 янв 2004
- Сообщения:
- 615
-
green
New Member
- Публикаций:
-
0
- Регистрация:
- 15 июл 2003
- Сообщения:
- 1.217
- Адрес:
- Ukraine
А на чём DLL написана? AddressOfEntryPoint может быть адресом ф-ции RTL, которя уже вызывает твою DllMain.
Так, для VC это DllMainCRTStartup.
Кстати DLL может и вовсе не иметь точки входа.
Типичный случай – resource only dll.
-
vovka
New Member
- Публикаций:
-
0
- Регистрация:
- 23 май 2006
- Сообщения:
- 45
Написал я свою маленькую DLL, вернее создал в VS2003!
Только Одна DllMain!
Когда делаю LoadLibrary! все ок!
т.е. DLL правильная!
Но найти аддресс DllMain не могу!
-
P_F
New Member
- Публикаций:
-
0
- Регистрация:
- 27 мар 2006
- Сообщения:
- 116
- Адрес:
- Russia
google на Рустэм PE Dll ничего не дал
как его найти
Рустэм == Roustem
Dll in binary [Roustem] ==Roustem – Dll в машинных кодах.
-
2 Roustem:
Слава богу ты не видел этого поста во вторник утром ))
Иначе бы я не знаю, чтобы ты написал подвоздействием того, чем я угощал в понедельник когда защитил дипломный проект ))
-
P_F
New Member
- Публикаций:
-
0
- Регистрация:
- 27 мар 2006
- Сообщения:
- 116
- Адрес:
- Russia
2 EvilsInterrupt:
2 Roustem:???
2 vovka:
А нафига вообще тебе DLL Main если не секрет? А то может можно и проще…
Кстати не знаю на сколько поможет Roustem, а вот на васме точно где то были очень хорошие доки по PE для exe и dll.
-
P_F
New Member
- Публикаций:
-
0
- Регистрация:
- 27 мар 2006
- Сообщения:
- 116
- Адрес:
- Russia
Вот неплохая дока:
(Документация по PE-файлам).zipCLR spec.doc
-
crypto
Active Member
- Публикаций:
-
0
- Регистрация:
- 13 дек 2005
- Сообщения:
- 2.533
EvilsInterrupt
Поздравляю с защитой. Какоя тема диплома?
-
vovka
New Member
- Публикаций:
-
0
- Регистрация:
- 23 май 2006
- Сообщения:
- 45
P_F
Вот разобрал весь DLL, а вот как найти DllMain не знаю!
Я смотрю вопрос тяжёлый, т.к. никто внятно не ответил, да и в доках я ничего не нашёл! Но ведь такого не может быть!!!
-
leo
Active Member
- Публикаций:
-
0
- Регистрация:
- 4 авг 2004
- Сообщения:
- 2.542
- Адрес:
- Russia
vovka
Тебе green уже ответил.
Если ты пишешь dll “ручками” на асме (или в кодах а ля Roustem), то твоя DllMain – “настоящая” и располагается по AddressOfEntryPoint
А вот во всяких ЯВУ добрые дяди из MS, Borland и т.п. пишут настоящую навороченную DllMain сами, а твоя DllMain – это лишь дополнительная пользовательская функция, которая вызывается из главной функции, автоматически создаваемой компилятором. Поэтому где находится именно твоя функция – зависит от компилятора. Поставь в начало int3 и посмотри в отладчике
-
vovka
New Member
- Публикаций:
-
0
- Регистрация:
- 23 май 2006
- Сообщения:
- 45
leo
я в отладчике видел!! Но найти не мог!
Так всё-таки есть какие-то идеи как её найти, т.е.
мою DllMain? Я в VS2003! Но ничего про этот механизм не сдышал!?
и всё-таки!
-
vovka
New Member
- Публикаций:
-
0
- Регистрация:
- 23 май 2006
- Сообщения:
- 45
leo
кстати в ida открывал свою dll, там явно и красиво
показано где начинается код DllMain!!!
прямо ужас какой-то!
-
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