Articles How to Use C Compiler for Reverse Engineering (pratically a hacker lesson)

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
[SHOWTOGROUPS=4,20,22]

Let's comment this function in module definition file:

Hide Copy Code
LIBRARY DLC

EXPORTS

_BinkSetPan@12 = binkw32._BinkSetPan@12
_BinkSetVolume@12 = binkw32._BinkSetVolume@12
_BinkGetError@0 = binkw32._BinkGetError@0
_BinkPause@8 = binkw32._BinkPause@8
_BinkOpen@8 = binkw32._BinkOpen@8
_BinkSetIO@4 = binkw32._BinkSetIO@4
_BinkSetSoundTrack@8 = binkw32._BinkSetSoundTrack@8
_BinkSetSoundSystem@8 = binkw32._BinkSetSoundSystem@8
_BinkOpenDirectSound@4 = binkw32._BinkOpenDirectSound@4

; _RADSetMemory@8 = binkw32._RADSetMemory@8

_BinkClose@4 = binkw32._BinkClose@4
_BinkNextFrame@4 = binkw32._BinkNextFrame@4
_BinkCopyToBufferRect@44 = binkw32._BinkCopyToBufferRect@44
_BinkDoFrame@4 = binkw32._BinkDoFrame@4
_BinkWait@4 = binkw32._BinkWait@4
_RADTimerRead@0 = binkw32._RADTimerRead@0
And provide our own implementation:

Hide Copy Code
typedef void *type_SomeFunctionPointer;
typedef void(__stdcall *type_binkw32_RADSetMemory)
(type_SomeFunctionPointer, type_SomeFunctionPointer);
type_binkw32_RADSetMemory binkw32_RADSetMemory;

void DLCInit()
{
...

HMODULE binkw32 = LoadLibraryA("binkw32.dll");
binkw32_RADSetMemory =
(type_binkw32_RADSetMemory)GetProcAddress(binkw32, "_RADSetMemory@8");
}

extern "C"
{
__declspec(dllexport) void __stdcall RADSetMemory
(type_SomeFunctionPointer f1, type_SomeFunctionPointer f2)
{
binkw32_RADSetMemory(f1, f2);
}
}
Let's build our dlc DLL with this small change, and verify its exports:

dumpbin /exports dlc.dll

26.jpg


We can debug it like any other code:

27.jpg



Why we bother to provide such stubs? This way, we can have reversed API interface expressed as C code, and we will immediately know if we didn't get it right (program will probably crash), because this function gets called actually. We can patch multiple import descriptors with our dlc DLL name, and either forward API to appropriate DLL, or provide our own stub as we advance through reverse process.

Now let's show 64-bit example. It will be port of doom3 source code called dhewm3:

We can build it as 64-bit, this is something that can't be done with official doom3 source code:

There is no prebuild 64-bit release for Windows. So we have to build our own. Though it is recommended to use MinGW for 64-bit build, I have managed to build 64-bit version with Visual Studio (with some project properties tuned). I successfully made it to game's main menu, the game still crushed in the middle of level loading (probably I should have used MinGW). However, it will do fine for our purpose.


[/SHOWTOGROUPS]
 

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
[SHOWTOGROUPS=4,20,22]
Let's see doom 3 imports:

dumpbin /imports dhewm3.exe

d0.jpg


d1.jpg



Let's stick to sdl2.dll. Redirect imports to file, so we can easily copy them to module definition file. Here is SDL2 part of dumpbin output:

Hide Shrink
arrow-up-16.png
Copy Code
SDL2.dll
1439BC3B0 Import Address Table
1439BD818 Import Name Table
0 time date stamp
0 Index of first forwarder reference

14C SDL_Quit
F1 SDL_HasAltiVec
F6 SDL_HasMMX
EF SDL_Has3DNow
F8 SDL_HasSSE
F9 SDL_HasSSE2
23 SDL_CreateMutex
124 SDL_LockMutex
1B9 SDL_UnlockMutex
37 SDL_DestroyMutex
21 SDL_CreateCond
36 SDL_DestroyCond
19 SDL_CondSignal
1A SDL_CondWait
2D SDL_CreateThread
FF SDL_Init
BC SDL_GetThreadID
1C7 SDL_WaitThread
35 SDL_Delay
93 SDL_GetModState
18A SDL_SetModState
149 SDL_PumpEvents
148 SDL_PollEvent
14A SDL_PushEvent
1EB SDL_malloc
1E0 SDL_getenv
200 SDL_strlen
1FF SDL_strlcpy
1FE SDL_strlcat
204 SDL_strrchr
1D7 SDL_atoi
25 SDL_CreateRGBSurfaceFrom
4C SDL_FreeSurface
2E SDL_CreateWindow
C7 SDL_GetWindowFlags
1A2 SDL_SetWindowIcon
D0 SDL_GetWindowSize
1A1 SDL_SetWindowGrab
1A0 SDL_SetWindowGammaRamp
3B SDL_DestroyWindow
56 SDL_GL_GetProcAddress
5B SDL_GL_SetAttribute
4F SDL_GL_CreateContext
5C SDL_GL_SetSwapInterval
5D SDL_GL_SwapWindow
50 SDL_GL_DeleteContext
18D SDL_SetRelativeMouseMode
1A9 SDL_ShowCursor
1C9 SDL_WasInit
8B SDL_GetError
BE SDL_GetTicks
2 SDL_AddTimer
C1 SDL_GetVersion
15D SDL_RemoveTimer
1B3 SDL_ThreadID

If we have too many functions, we can automate the process of def file creation. For example, we can remove headers and replace this text (regular expression):

Hide Copy Code
.*SDL_ # any characters before "SDL_" and "SDL_" itself
with this:

Hide Copy Code
SDL_
Next, we create module definition file for sdl2.dll (this time, we will need it). And put all functions inside it:

sdl2.def:

Hide Shrink
arrow-up-16.png
Copy Code
LIBRARY SDL2

EXPORTS

SDL_Quit
SDL_HasAltiVec
SDL_HasMMX
SDL_Has3DNow
SDL_HasSSE
SDL_HasSSE2
SDL_CreateMutex
SDL_LockMutex
SDL_UnlockMutex
SDL_DestroyMutex
SDL_CreateCond
SDL_DestroyCond
SDL_CondSignal
SDL_CondWait
SDL_CreateThread
SDL_Init
SDL_GetThreadID
SDL_WaitThread
SDL_Delay
SDL_GetModState
SDL_SetModState
SDL_PumpEvents
SDL_PollEvent
SDL_PushEvent
SDL_malloc
SDL_getenv
SDL_strlen
SDL_strlcpy
SDL_strlcat
SDL_strrchr
SDL_atoi
SDL_CreateRGBSurfaceFrom
SDL_FreeSurface
SDL_CreateWindow
SDL_GetWindowFlags
SDL_SetWindowIcon
SDL_GetWindowSize
SDL_SetWindowGrab
SDL_SetWindowGammaRamp
SDL_DestroyWindow
SDL_GL_GetProcAddress
SDL_GL_SetAttribute
SDL_GL_CreateContext
SDL_GL_SetSwapInterval
SDL_GL_SwapWindow
SDL_GL_DeleteContext
SDL_SetRelativeMouseMode
SDL_ShowCursor
SDL_WasInit
SDL_GetError
SDL_GetTicks
SDL_AddTimer
SDL_GetVersion
SDL_RemoveTimer
SDL_ThreadID
Invoke the following command to produce import lib file:

Hide Copy Code
lib /def:sdl2.def /out:sdl2.lib /machine:x64

[/SHOWTOGROUPS]
 

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
[SHOWTOGROUPS=4,20,22]

You will get sdl2.lib file that we will need to link against in our dlc DLL. Now let's create module definition file for dlc DLL. Make a copy of sdl2.def file and delete "LIBRARY SDL2" and "EXPORTS" lines, let's name it sdl2.txt. We can use the following python script:

gen.py:

Hide Copy Code
file = open("dlc.def", "w")
file.write("LIBRARY DLC\n")
file.write("EXPORTS\n")
for i, line in enumerate(open("sdl2.txt", "r")):
line = line.strip("\n")
format = "%s = sdl2.%s\n"
file.write(format % (line, line))
file.close()
Run the script:

Hide Copy Code
python gen.py
We will get the following dlc def file:

Hide Shrink
arrow-up-16.png
Copy Code
LIBRARY DLC
EXPORTS
SDL_Quit = sdl2.SDL_Quit
SDL_HasAltiVec = sdl2.SDL_HasAltiVec
SDL_HasMMX = sdl2.SDL_HasMMX
SDL_Has3DNow = sdl2.SDL_Has3DNow
SDL_HasSSE = sdl2.SDL_HasSSE
SDL_HasSSE2 = sdl2.SDL_HasSSE2
SDL_CreateMutex = sdl2.SDL_CreateMutex
SDL_LockMutex = sdl2.SDL_LockMutex
SDL_UnlockMutex = sdl2.SDL_UnlockMutex
SDL_DestroyMutex = sdl2.SDL_DestroyMutex
SDL_CreateCond = sdl2.SDL_CreateCond
SDL_DestroyCond = sdl2.SDL_DestroyCond
SDL_CondSignal = sdl2.SDL_CondSignal
SDL_CondWait = sdl2.SDL_CondWait
SDL_CreateThread = sdl2.SDL_CreateThread
SDL_Init = sdl2.SDL_Init
SDL_GetThreadID = sdl2.SDL_GetThreadID
SDL_WaitThread = sdl2.SDL_WaitThread
SDL_Delay = sdl2.SDL_Delay
SDL_GetModState = sdl2.SDL_GetModState
SDL_SetModState = sdl2.SDL_SetModState
SDL_PumpEvents = sdl2.SDL_PumpEvents
SDL_PollEvent = sdl2.SDL_PollEvent
SDL_PushEvent = sdl2.SDL_PushEvent
SDL_malloc = sdl2.SDL_malloc
SDL_getenv = sdl2.SDL_getenv
SDL_strlen = sdl2.SDL_strlen
SDL_strlcpy = sdl2.SDL_strlcpy
SDL_strlcat = sdl2.SDL_strlcat
SDL_strrchr = sdl2.SDL_strrchr
SDL_atoi = sdl2.SDL_atoi
SDL_CreateRGBSurfaceFrom = sdl2.SDL_CreateRGBSurfaceFrom
SDL_FreeSurface = sdl2.SDL_FreeSurface
SDL_CreateWindow = sdl2.SDL_CreateWindow
SDL_GetWindowFlags = sdl2.SDL_GetWindowFlags
SDL_SetWindowIcon = sdl2.SDL_SetWindowIcon
SDL_GetWindowSize = sdl2.SDL_GetWindowSize
SDL_SetWindowGrab = sdl2.SDL_SetWindowGrab
SDL_SetWindowGammaRamp = sdl2.SDL_SetWindowGammaRamp
SDL_DestroyWindow = sdl2.SDL_DestroyWindow
SDL_GL_GetProcAddress = sdl2.SDL_GL_GetProcAddress
SDL_GL_SetAttribute = sdl2.SDL_GL_SetAttribute
SDL_GL_CreateContext = sdl2.SDL_GL_CreateContext
SDL_GL_SetSwapInterval = sdl2.SDL_GL_SetSwapInterval
SDL_GL_SwapWindow = sdl2.SDL_GL_SwapWindow
SDL_GL_DeleteContext = sdl2.SDL_GL_DeleteContext
SDL_SetRelativeMouseMode = sdl2.SDL_SetRelativeMouseMode
SDL_ShowCursor = sdl2.SDL_ShowCursor
SDL_WasInit = sdl2.SDL_WasInit
SDL_GetError = sdl2.SDL_GetError
SDL_GetTicks = sdl2.SDL_GetTicks
SDL_AddTimer = sdl2.SDL_AddTimer
SDL_GetVersion = sdl2.SDL_GetVersion
SDL_RemoveTimer = sdl2.SDL_RemoveTimer
SDL_ThreadID = sdl2.SDL_ThreadID
Comment out the following lines:

Hide Copy Code
SDL_HasMMX = sdl2.SDL_HasMMX
SDL_Has3DNow = sdl2.SDL_Has3DNow
SDL_HasSSE = sdl2.SDL_HasSSE
SDL_HasSSE2 = sdl2.SDL_HasSSE2
SDL_HasAltiVec = sdl2.SDL_HasAltiVec
just like this:

Hide Copy Code
; SDL_HasMMX = sdl2.SDL_HasMMX
; SDL_Has3DNow = sdl2.SDL_Has3DNow
; SDL_HasSSE = sdl2.SDL_HasSSE
; SDL_HasSSE2 = sdl2.SDL_HasSSE2
; SDL_HasAltiVec = sdl2.SDL_HasAltiVec
We will provide our own stubs, since we will have to call this API ourselves. Now let's turn our attention to dlc DLL code. We will pick the following function:

d2.jpg


Let's open EXE in IDA and find this function:

d3.jpg

[/SHOWTOGROUPS]
 

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
[SHOWTOGROUPS=4,20,22]
d4.jpg


d5.jpg


d6.jpg


d7.jpg


d7.jpg


d8.jpg



[/SHOWTOGROUPS]
 

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
[SHOWTOGROUPS=4,20,22]

Let's see the code:

Hide Shrink
arrow-up-16.png
Copy Code
#include <Windows.h>

#pragma pack(push, 1)
typedef struct _Sorry // 12 bytes of space needed
{
struct
{
BYTE Force64bit;
BYTE Opcode;
INT64 Value;
} MovToRax; // mov rax, func
struct
{
BYTE Opcode;
BYTE Reg;
} JmpRax; // jmp rax
} Sorry;
#pragma pack(pop)

const unsigned long long DefExeBase = 0x140000000;
BYTE *g_ExeBase;

typedef int(*type_sdl2_api)();
type_sdl2_api sdl2_HasMMX;
type_sdl2_api sdl2_Has3DNow;
type_sdl2_api sdl2_HasSSE;
type_sdl2_api sdl2_HasSSE2;
type_sdl2_api sdl2_HasAltiVec;

void DLCInit()
{
g_ExeBase = (BYTE*)GetModuleHandleA(NULL);
DLCBindGlobals();
DLCBindFunctions();

HMODULE sdl2 = LoadLibraryA("SDL2.dll");
sdl2_HasMMX = (type_sdl2_api)GetProcAddress(sdl2, "SDL_HasMMX");
sdl2_Has3DNow = (type_sdl2_api)GetProcAddress(sdl2, "SDL_Has3DNow");
sdl2_HasSSE = (type_sdl2_api)GetProcAddress(sdl2, "SDL_HasSSE");
sdl2_HasSSE2 = (type_sdl2_api)GetProcAddress(sdl2, "SDL_HasSSE2");
sdl2_HasAltiVec = (type_sdl2_api)GetProcAddress(sdl2, "SDL_HasAltiVec");
}

void DLCBindGlobals()
{
// we don't use globals in our function, so nothing here
}

void DLCReplaceFunction(BYTE *OldFunc, BYTE *NewFunc)
{
Sorry *s = (Sorry*)OldFunc;
s->MovToRax.Force64bit = 0x48;
s->MovToRax.Opcode = 0xb8;
s->MovToRax.Value = (INT64)NewFunc;
s->JmpRax.Opcode = 0xff;
s->JmpRax.Reg = 0xe0;
}

void DLCBindFunctions()
{
DLCReplaceFunction(g_ExeBase + (0x1402E3F50 - DefExeBase), (BYTE*)sub_1402E3F50);
}

typedef enum
{
CPUID_DEFAULT = 0x00002,
CPUID_MMX = 0x00010,
CPUID_3DNOW = 0x00020,
CPUID_SSE = 0x00040,
CPUID_SSE2 = 0x00080,
CPUID_ALTIVEC = 0x00200,
};

extern "C"
{
__declspec(dllexport) int SDL_HasMMX()
{
return sdl2_HasMMX();
}

__declspec(dllexport) int SDL_Has3DNow()
{
return sdl2_Has3DNow();
}

__declspec(dllexport) int SDL_HasSSE()
{
return sdl2_HasSSE();
}

__declspec(dllexport) int SDL_HasSSE2()
{
return sdl2_HasSSE2();
}

__declspec(dllexport) int SDL_HasAltiVec()
{
return sdl2_HasAltiVec();
}
}

int sub_1402E3F50()
{
int flags = CPUID_DEFAULT;

if (SDL_HasMMX())
flags |= CPUID_MMX;

// DLC extra
//if (SDL_Has3DNow())
flags |= CPUID_3DNOW;

if (SDL_HasSSE())
flags |= CPUID_SSE;

if (SDL_HasSSE2())
flags |= CPUID_SSE2;

// DLC extra
//if (SDL_HasAltiVec())
flags |= CPUID_ALTIVEC;

return flags;
}

BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
DLCInit();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
I don't have 3DNow and AltiVec support on my CPU, so I modified the function a little. This mod produced no visual side effect (sadly, game didn't even crash), however for our example, it will do. Also, we have to call some sdl2 API here, that's why we immediately follow our idea to express module-to-module interface as C code.

One note here: if you have 32-bit program and will follow the same scheme:

Comment function in def file:

Hide Copy Code
; Api = some_dll.Api
and put it in code:

Hide Copy Code
extern "C"
{
__declspec(dllexport) int Api(int param) { ... }
}
You will have Api function with __cdecl calling convention. However, it is possible to export __stdcall functions from 32-bit DLL without any name decoration (with def file, and not with __declspec(dllexport)). You should inspect program's disassembly to see whether it is __cdecl or __stdcall. If it is __stdcall, and your function is __cdecl, the crash is possible because your function doesn't clean up stack from its parameters, and inspected program expects that it does. To solve this problem, you will need to do the following:

def file:

Hide Copy Code
Api = _Api@4
The code is as follows:

Hide Copy Code
extern "C"
{
int __stdcall Api(int param) { ... }
}
In this case, exported name is not decorated, and function is __stdcall, as expected.


[/SHOWTOGROUPS]
 

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
[SHOWTOGROUPS=4,20,22]
Now back to 64-bit example. Let's add -debug-wait. Here's start_0 function (start is just a jump to start_0, so we don't have enough space to write Sorry structure):

e0.jpg


Let's see its address:

e1.jpg



-debug-wait implementation is no different from 32-bit:

Hide Shrink
arrow-up-16.png
Copy Code
typedef int(*Start)(); // __stdcall no longer needed

Start start_ptr;
Sorry start_sorry;

void DLCInit()
{
char *_cmd = GetCommandLineA();
std::string cmd(_cmd);
std::string suffix("-debug-wait");
std::size_t found = cmd.find(suffix);
bool debug_wait = false;

while (found != std::string::npos)
{
if (cmd.length() == (found + suffix.length()))
{
_cmd[found] = 0; // probably we should hide this parameter from program
debug_wait = true;
break;
}
found = cmd.find(suffix, found + 1);
}

g_ExeBase = (BYTE*)GetModuleHandleA(NULL);
DLCBindGlobals();
DLCBindFunctions();
if (debug_wait) DLCWaitForDebugger();

...
}

void DLCWaitForDebugger()
{
start_ptr = (Start)(g_ExeBase + (0x1403F59A0 - DefExeBase));
start_sorry = *((Sorry*)start_ptr);
DLCReplaceFunction((BYTE*)start_ptr, (BYTE*)sub_1403F59A0);
}

int sub_1403F59A0()
{
*((Sorry*)start_ptr) = start_sorry;
while (!IsDebuggerPresent()) Sleep(500);
DebugBreak();
return start_ptr();
}
Now let's see the full code:

Hide Shrink
arrow-up-16.png
Copy Code
#include <Windows.h>
#include <string>

#pragma pack(push, 1)
typedef struct _Sorry // 12 bytes of space needed
{
struct
{
BYTE Force64bit;
BYTE Opcode;
INT64 Value;
} MovToRax; // mov rax, func
struct
{
BYTE Opcode;
BYTE Reg;
} JmpRax; // jmp rax
} Sorry;
#pragma pack(pop)

const unsigned long long DefExeBase = 0x140000000;
BYTE *g_ExeBase;

typedef int(*Start)(); // __stdcall no longer needed

Start start_ptr;
Sorry start_sorry;

typedef int(*type_sdl2_api)();
type_sdl2_api sdl2_HasMMX;
type_sdl2_api sdl2_Has3DNow;
type_sdl2_api sdl2_HasSSE;
type_sdl2_api sdl2_HasSSE2;
type_sdl2_api sdl2_HasAltiVec;

void DLCInit()
{
char *_cmd = GetCommandLineA();
std::string cmd(_cmd);
std::string suffix("-debug-wait");
std::size_t found = cmd.find(suffix);
bool debug_wait = false;

while (found != std::string::npos)
{
if (cmd.length() == (found + suffix.length()))
{
_cmd[found] = 0; // probably we should hide this parameter from program
debug_wait = true;
break;
}
found = cmd.find(suffix, found + 1);
}

g_ExeBase = (BYTE*)GetModuleHandleA(NULL);
DLCBindGlobals();
DLCBindFunctions();
if (debug_wait) DLCWaitForDebugger();

HMODULE sdl2 = LoadLibraryA("SDL2.dll");
sdl2_HasMMX = (type_sdl2_api)GetProcAddress(sdl2, "SDL_HasMMX");
sdl2_Has3DNow = (type_sdl2_api)GetProcAddress(sdl2, "SDL_Has3DNow");
sdl2_HasSSE = (type_sdl2_api)GetProcAddress(sdl2, "SDL_HasSSE");
sdl2_HasSSE2 = (type_sdl2_api)GetProcAddress(sdl2, "SDL_HasSSE2");
sdl2_HasAltiVec = (type_sdl2_api)GetProcAddress(sdl2, "SDL_HasAltiVec");
}

void DLCBindGlobals()
{
// we don't use globals in our function, so nothing here
}

void DLCReplaceFunction(BYTE *OldFunc, BYTE *NewFunc)
{
Sorry *s = (Sorry*)OldFunc;
s->MovToRax.Force64bit = 0x48;
s->MovToRax.Opcode = 0xb8;
s->MovToRax.Value = (INT64)NewFunc;
s->JmpRax.Opcode = 0xff;
s->JmpRax.Reg = 0xe0;
}

void DLCBindFunctions()
{
DLCReplaceFunction(g_ExeBase + (0x1402E3F50 - DefExeBase), (BYTE*)sub_1402E3F50);
}

void DLCWaitForDebugger()
{
start_ptr = (Start)(g_ExeBase + (0x1403F59A0 - DefExeBase));
start_sorry = *((Sorry*)start_ptr);
DLCReplaceFunction((BYTE*)start_ptr, (BYTE*)sub_1403F59A0);
}

int sub_1403F59A0()
{
*((Sorry*)start_ptr) = start_sorry;
while (!IsDebuggerPresent()) Sleep(500);
DebugBreak();
return start_ptr();
}

typedef enum
{
CPUID_DEFAULT = 0x00002,
CPUID_MMX = 0x00010,
CPUID_3DNOW = 0x00020,
CPUID_SSE = 0x00040,
CPUID_SSE2 = 0x00080,
CPUID_ALTIVEC = 0x00200,
};

extern "C"
{
__declspec(dllexport) int SDL_HasMMX()
{
return sdl2_HasMMX();
}

__declspec(dllexport) int SDL_Has3DNow()
{
return sdl2_Has3DNow();
}

__declspec(dllexport) int SDL_HasSSE()
{
return sdl2_HasSSE();
}

__declspec(dllexport) int SDL_HasSSE2()
{
return sdl2_HasSSE2();
}

__declspec(dllexport) int SDL_HasAltiVec()
{
return sdl2_HasAltiVec();
}
}

int sub_1402E3F50()
{
int flags = CPUID_DEFAULT;

if (SDL_HasMMX())
flags |= CPUID_MMX;

// DLC extra
//if (SDL_Has3DNow())
flags |= CPUID_3DNOW;

if (SDL_HasSSE())
flags |= CPUID_SSE;

if (SDL_HasSSE2())
flags |= CPUID_SSE2;

// DLC extra
//if (SDL_HasAltiVec())
flags |= CPUID_ALTIVEC;

return flags;
}

BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
DLCInit();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

[/SHOWTOGROUPS]
 

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
[SHOWTOGROUPS=4,20,22]
Build dlc DLL as 64-bit and copy it to game's folder. Now, it's time to see file offsets:

e5.jpg


e6.jpg


Make a copy of dhewm3.exe and open it in hex editor:

e7.jpg


e8.jpg


And patch it:

e9.jpg


e10.jpg



Now we can run our patched doom 3 and enjoy the game.

Conclusion
We demonstated the concept of using C compiler in reverse engineering process. It's handy because we can write real code and test it, we have all advantages of real programming language. We can have one dlc DLL for each image of the program we are reversing (just like IDA database).

We should mention what to do with small functions. So small, that we can't write our Sorry structure at the beginning without overwriting another function or data. Well, if the function is small, it is easy to understand. We can still write our own version of it, it just won't get called.

Of course, things will likely fail if image contains self modifying code, or checks whether it has been patched, or another anti-reverse tricks. However, we are discussing reverse engineering approach here, not solving anti-debugging tricks.

Some things were not covered. For example, forwarding of data imports, and C++ kind of things. We can't cover everything, also C++ makes things more complex. I would stick to C, and compensate this lack of C++ expression with good program design (for example, separate "classes" in separate .c files) and good comments. Later, when we have enough information, and if we clearly see that we can use C++, we will take advantage of C++ capabilities.

Another important thing: this approach requires code writing, and helps you to feel like actual programmer, not only intruder. We can translate functions to C one by one, and slowly change the role of "intruder in hostile executable written by another dudes" to "creator, writer of the code". Something like: of course I know how it works, I have written it myself!

We need to store the particular version of the program we are reversing, together with our dlc DLLs. It is because our dlc DLL is made to work with particular image. If update happens and executable changes (think of all those hardcoded function offsets), our dlc will likely stop working. So we need to have original version of program, and when update happens, we can also update our dlc DLL to work with new executable. This way, we can slowly cut into program and keep things up to date.

I am going to try this approach myself. I want to make some mod for this old Hulk game (for example, add new hulk attack). I really liked it when I was a kid, it's cool to smash everything.

I wish you good luck in all your reverse engineering endeavors. May the force of C compiler be with you. Thank you for reading.


[/SHOWTOGROUPS]