Jump to content
Tuts 4 You

Dynamic DLL?


SunBeam

Recommended Posts

Hello, guys and gals. I have a question involving patching system DLLs to allow hooking or loading of user's modules inside an app. For instance, I picked msvcrt.dll from system32 for this task. Loading up the DLL in Olly shows this:

16awqxe.png

So, let's say I want to write some code inside the DLL, then place a JMP or PUSH+RET at DLL's EP to redirect it to first execute my code, then restore code at EP, after which I'll resume execution to the DLL. All easy and done, I pick some empty space from .data section, as below:

b8nw9v.png

So,

EP: 77C1F2A1

CAVE: 77C5D300

It would work pretty well, except, if I copy DLL to Desktop and open it in Olly, I get this:

k01ohe.png

Under these circumstances it is obvious that if I plant a JMP or PUSH+RET at EP to point it to a cave, it would point to an erroneous spot in memory o_O. Given this analysis, what would the correct 'hooking' action be under these circumstances?

P.S.: I know you'll say "because of .reloc". Well, so what? :-)

Link to comment

So why don't you just subtract the base from the addresses and then when applying the patch add the relocated base of the module back?

Edited by high6
Link to comment

^ Example please, given the already posted addressing? I mean, I don't know how to reference the CAVE at EP, since I have to write this:

EP: 77C1F2A1 -> JMP 77C5D300

But if I load DLL from Desktop, I will see this:

EP: 87F2A1 -> JMP 77C5D300 (instead of 87x300)

That would mean I have to hook the DLL's reloc :-) That would be like scratching my left ear with my right hand. Point is I don't know the address where DLL is "relocated" BEFORE I write my data at OEP o_O. I am guessing that on different OSes, it would be placed at different addresses..

EDIT: PUSH + RET won't work, but RELATIVE JMPs do the trick ;-) "JMP cave" is offseted the same no matter where file gets loaded..

Edited by SunBeam
Link to comment

Are you limiting yourself to the amount of work you want to do @ the EP? If no, you could allocate memory via VirtualAlloc and write your code to the allocated memory then call/jmp to it, handle it, rewrite the EP and continue. Would be extra work, but it should get the job done.

Link to comment

Another way: GetModuleHandle (0) to get the ImageBase, and then add to your known OEP (RVA)... That's the address of the OEP (VA). ;)

Edited by Nacho_dj
Link to comment

Ok, you all omitted one thing. I have to plant a JMP or PUSH+RET at DLL's EP. And to do that, I have to tell it to jump to a hardcoded address. I don't have enough room at target's EP to do GetModuleHandle and plant a DYNAMIC JMP.. That's what I was saying all along.. Your replies are OK, but don't apply to my case, the way I put it in the lines above. So, I am guessing it works like this:

- find a cave inside the DLL's raw code;

- in the cave, write your code (including GetModuleHandle(x) stuff);

- calculate the OEP from result above (return + offset);

- write the JMP [ xxxxxxxx ];

What I meant is it doesn't work in this way:

- OEP: JMP cave <- how do you calculate 'cave'`s address if you don't know where DLL is located/relocated??

- all the above

Link to comment

You have to know the module base before patching anything.

Once you have that, you can calculate the EP using the RVA, you can write a relative JMP to the cave, and a relative jump back from the cave to the EP.

So there's obviously no way around calling GetModuleHandle or parsing the PEB if you can't add any extra imports or don't have a call to GetModuleHandle somewhere already.

Well you could patch msvcrt and copy it to the program folder, not that nice though if this is going anywhere outside your PC.

Link to comment
GamingMasteR

Injected code looks like this :

call $+5	; 0e8h, 000h, 000h, 000h, 000h; push return address
pop eax ; 058h ; pop return address which is this current line
add eax, 50h; 083h, 0c0h, 050h ; add cave offset, calculated in injection-time
jmp eax ; 0ffh, 0e0h ; jump to cave

Only 11 bytes needed

Link to comment

^ Claps @ GamingMasteR :-) I like you already ;-)

EDIT: Let's complicate it a bit, shall we, GamingMasteR? :-) What if.. I want to copy OEP bytes to the cave or to a backup pointer before planting that 11-bytes code? There's no way I could do it, eh, other than recreating it manually in the cave? Or rebuilding it back at OEP.. FROM.. the cave :-)..

Edited by SunBeam
Link to comment
GamingMasteR

Hi SunBeam,

I don't know other ways than :

1- Executing the stolen bytes after your stub in the cave .

2- Restoring the stolen bytes and jmp to it in OEP after your executing your stub .

Maybe searching for some hook engines will give you more views .

Link to comment

SunBeam, in the following thread of ARTeam board I suggested an autodeletion codecave, restoring the original bytes after its execution.

http://www.accessroot.com/arteam/forums/index.php?showtopic=5547&st=0

Maybe it would help for your ideas... ;)

Cheers

Nacho_dj

Link to comment
ahmadmansoor

Dear friend : :D

I don't know why u ask for this ,except that u prepare to make a kind of Crack for a program ;) .

I have Vista SP1 and I have search for ur file in my system32 ,without any chance to find it :P .

small story : :wacko:

Anyway , before I have Cracked a program by make a small debugger and put a bp at address of API and then patch the eax their

Edited by ahmadmansoor
Link to comment

Here's the whole purpose of this thread, to make it clear for all of you :-) Think you deserve the explanation :-P

I have this game that uses ddraw.dll (DirectX 7 old game) and a wrapper - wrap.dll. The wrapper is used only for DirectDrawCreate function. The other APIs are untouched. So, if I am to use a no-cd crack (removed protection - game uses old SafeDisc, but still..) I can easily find the string_refs (ddraw.dll appears twice in the game's .exe, once for DirectDrawCreate, second for DirectDrawEnumerateDevices or something..). Things get complicated when using the original game bought from shop - file is encrypted, can't clearly see strings.

The idea is to force the game to load wrap.dll instead of ddraw.dll when game wants to get the address of DirectDrawCreate, thus swapping original function with the fake one.

So, since I can't touch the .exe (encrypted), I thought I'd drop in via a hook. Can't use IAT of the file, since it doesn't contain refs to LoadLibraryA. So, only way to make this global is to use a module game loads. I had to choose between msvcrt.dll and winmm.dll. Since the last one (winmm) contains only W versions of APIs (and hence why my code would get bigger - GetModuleHandle, GetProcAddress etc.. to get VirtualProtect and deprotect LoadLibraryA), I chose msvcrt.dll.

Now I want to patch this DLL, drop it in game's folder and let it do all the dirty job. Code goes like this:

cave_in_DLL:

pushad

pushfd

..

get_VirtualProtect_addr

push args

deprotect_LoadLibraryA

hook_LoadLibraryA (push + ret) // or GamingMasteR's method

restore_bytes_@_OEP

popfd

popad

jmp_OEP

LoadLibraryA:

jmp hook_cave (push + ret or w.e.)

hook_cave:

cmp [ptr+offset]_for_BOOL

check_if_func_is_DirectDrawCreate

swap_ddraw.dll_for_wrap.dll

if_done_restore_LoadLibraryA

Something on the lines of that :-)

@ahmadmansoor: Sorry, SafeDisc dislikes debuggers :-))

Edited by SunBeam
Link to comment

SunBeam, think of it like this mate:

* A relative CALL takes up 5 bytes and doesnt need relocating, so you can patch the OEP to CALL your codecave.

* Subtract 5 from the return address in the stack and you have the OEP you need to return to.

* Using the 'GetDelta' method, you can reference anything within the dll image.

* Using the hInstance member of the call to DllMain, you can then relocate any other references.

Real life example:

[Patched Entrypoint]
105C226E:
CALL 105CD30D
JNZ SHORT 105C227A[Code Cave @ 105CD30D]
SUB DWORD PTR SS:[ESP],5;<-- Correct return address
PUSHAD;<-- Save registers
PUSHFD;<-- Save eFlags
CALL 105CD318;<-- Get delta105CD318:
5D POP EBP <-- Set EBP to be reference point
MOV EAX,DWORD PTR SS:[ESP+2C];<-- Use hInstance from stack
ADD DWORD PTR SS:[EBP+1E1],EAX;<-- To make offsets into absolute virtual addresses
ADD DWORD PTR SS:[EBP+1E5],EAX;<-- ditto; OEP restore code goes here...
; Then hook code is here...POPFD; <-- Restore eFlags
POPAD; <-- Restore registers
RET; <-- Return to OEP

[Accessing code/data via EBP]

PUSH DWORD PTR SS:[EBP+1DD] ; <-- one way to access things from EBP

LEA EAX,DWORD PTR SS:[EBP+1D8] <-- another way to access the data

PUSH EAX

LEA EAX,DWORD PTR SS:[EBP+18F] <-- a way to call a function directly

CALL EAX

CALL DWORD PTR SS:[EBP+18F] <-- a way to access the DWORD, if it were an address

If you are familiar with using MASM, you can code your entire cave in assembler (making sure to not hard code any addresses, etc, only offsets if necessary) and then assemble it and copy the code.

This makes it as simple as using:

PUSHAD
PUSHFD
CALL GetDelta
GetDelta:
POP EBP
;Lets place the address of our test string in EAX
LEA EAX, DWORD PTR [EBP + (offset szTestString - offset GetDelta)];Lets get the contents of a DWORD buffer and place it in EAX
MOV EAX, DWORD PTR [EBP + (offset dwTestValue - offset GetDelta)];Now lets get the offset of a function, add the hInstance to make it absolute, then call it.
LEA EAX, DWORD PTR [EBP + (offset szTestString - offset GetDelta)]
PUSH EAX
PUSH DWORD PTR [EBP + (offset dwTestValue - offset GetDelta)]
MOV EAX, DWORD PTR [EBP + (offset dwTestValue - offset GetDelta)]
ADD EAX, DWORD PTR [ESP+2Ch]
CALL EAXPOPFD
POPAD
RETszString db "This is a test string",0
dwTestValue dd 0BAADF00Dh

Now the last example shows using 3 methods to access data/code and all 3 in the final example, where the address of the string is pushed, the contents of the DWORD are pushed as second param and then a function offset is used to make an absolute address which is called, with the other 2 pushes becoming the parameters for the call.

Remember if you are accessing C code, chances are you will need to adjust the stack yourself, because it is __cdecl and not __stdcall.

Lastly mate, relative CALL/JMP have no need for relocating, as they are measured from the origin of the call to the destination, hence the relative tag. So, this means if your dll loads at 0x10000000 and the JMP is inserted at 0x10001000 and it is jumping to 0x10002000, it would be E9 FB 0F 00 00.

Now when the dll is reloaded at another imagebase, say 0x20000000, the JMP will now be at 0x20001000 and the destination will be 0x20002000, no relocating necessary.

HR,

Ghandi

Edited by ghandi
Link to comment

^ Your reply is very much welcome. This thread proved to be an inspirational one after all. Big thanks to all of you people, you rock ;-) Now, enough ***-kissing and back to work! :-)

Link to comment
ahmadmansoor
@ahmadmansoor: Sorry, SafeDisc dislikes debuggers :-))

my friend the program which I Cracked is protected by SafeDisc the last ver ;) and it work very fine .

my friend when u run the exe file see the temp file ....

sometimes it Create a file f5s9556ww.tmp like this , just rename it to anything with .exe extension ;)

Link to comment

^ Hi. I know how SafeDisc works, that's not what I'm worried about - but reaching the decrypted strings through any means. Since I can't hex edit the file (code crypted), that's the only way - hooks :-)

Link to comment
Peter Ferrie

LoadLibrary looks in the current directory first. Why not place a ddraw.dll there, which forwards everything to the real ddraw, except for the one function that you want to hook?

Or suspend the process, inject a new thread that can be as large as you like, and which can perform the full code patch, hook whatever APIs you like, etc...

GetProcAddress doesn't have a W version. Only the GetModuleHandle does, so the only size increase is for the name of the DLL, but you don't need the ".DLL" part because Windows will add it for you. It's not so bad.

You also don't need push/ret - you can use e9 and calculate the difference easily. 5 bytes instead of 6.

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...