• Welcome to Valhalla Legends Archive.
 

Injecting a DLL via SetWindowsHookEx

Started by NicoQwertyu, November 15, 2004, 06:28 PM

Previous topic - Next topic

NicoQwertyu

#15
Do you guys know of anything else that could be wrong with the code I have thus far?  After the DLL is injected, two message boxes pop up informing me that "CALC.exe caused in error in <unknown>", then closes.  

I'm at school, but when I get home I'll try to debug it.  I'm pretty new to this though, so any input would be appreciated.

iago

There are tons of things that can go wrong when injecting assembly, but the major things are:
- Make sure ESP DOESN'T CHANGE
- Make sure you preserve all registers that are used after your patch
- Make sure you're returning to the correct address

The first two are the same, basically, but it's VERY important that the stack be EXACTLY the same when you return.  Also don't forget that call and ret both modify the stack pointer.

Debugging it, and stepping through the area where you made the patch, keeping track of registers, is probably your best bet.
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


Skywing

I typically use one of the following:


const unsigned long jmpdest = 0xnnnnnnnn;

.
.
.

jmp dword ptr [jmpdest]


Or...


mov eax, 0xnnnnnnnn
jmp eax

NicoQwertyu

#18
Quote from: iago on November 17, 2004, 12:24 PM
There are tons of things that can go wrong when injecting assembly, but the major things are:
- Make sure ESP DOESN'T CHANGE
- Make sure you preserve all registers that are used after your patch
- Make sure you're returning to the correct address

The first two are the same, basically, but it's VERY important that the stack be EXACTLY the same when you return.  Also don't forget that call and ret both modify the stack pointer.

Debugging it, and stepping through the area where you made the patch, keeping track of registers, is probably your best bet.

After stepping through it in a debugger: my code executes, jumps to the correct address, does what I want it to, hits a "retn 0", then ends up somewhere else where it, according to the debugger, has an "access violation when reading [FFFFFFFF]".  How can I fix whatever's going wrong?  :-[


[Edit]
The instruction it keeps getting stuck on is:
0x0056F362  0000  ADD BYTE PTR DS:[EAX], AL

drivehappy

@NicoQwertyu: Can you post stack information before your code is executed and then again at the jmp? Can you also post some more instructions before the access violation one?
@MyndFyre: I had meant EIP, it could very well be incorrect though (I'm used to 8051).

NicoQwertyu

Quote from: drivehappy on November 17, 2004, 02:04 PM
@NicoQwertyu: Can you post stack information before your code is executed and then again at the jmp? Can you also post some more instructions before the access violation one?
@MyndFyre: I had meant EIP, it could very well be incorrect though (I'm used to 8051).

I'd be more than happy to.

...

This is around my 4th time using a debugger, what exactly am I posting when you ask for "stack information?"

Sorry for my ignorance. :/

MyndFyre

Quote from: NicoQwertyu on November 17, 2004, 01:37 PM
After stepping through it in a debugger: my code executes, jumps to the correct address, does what I want it to, hits a "retn 0", then ends up somewhere else where it, according to the debugger, has an "access violation when reading [FFFFFFFF]".  How can I fix whatever's going wrong?  :-[

It's hitting a ret instruction?  Perhaps you need to use call rather than jmp in your code.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

NicoQwertyu

Quote from: MyndFyre on November 17, 2004, 03:03 PM
Quote from: NicoQwertyu on November 17, 2004, 01:37 PM
After stepping through it in a debugger: my code executes, jumps to the correct address, does what I want it to, hits a "retn 0", then ends up somewhere else where it, according to the debugger, has an "access violation when reading [FFFFFFFF]".  How can I fix whatever's going wrong?  :-[

It's hitting a ret instruction?  Perhaps you need to use call rather than jmp in your code.

That wouldn't work for what I want it to do.  And it should hit a ret, shouldn't it?  The address I jump to is in the middle of a function.   :o

drivehappy

Quote from: NicoQwertyu on November 17, 2004, 03:13 PM
Quote from: MyndFyre on November 17, 2004, 03:03 PM
Quote from: NicoQwertyu on November 17, 2004, 01:37 PM
After stepping through it in a debugger: my code executes, jumps to the correct address, does what I want it to, hits a "retn 0", then ends up somewhere else where it, according to the debugger, has an "access violation when reading [FFFFFFFF]".  How can I fix whatever's going wrong?  :-[

It's hitting a ret instruction?  Perhaps you need to use call rather than jmp in your code.

That wouldn't work for what I want it to do. And it should hit a ret, shouldn't it? The address I jump to is in the middle of a function. :o
That's probably your problem. When that function is called it pushes values onto the stack that correspond to parameters and the address at which it was called. Return I *believe* will revert EIP to the original address after which the call statement was made, any parameters should be popped off within the function. Again, I'm not 100% sure of the order. So when you jump inside the function and ret is reached it will try popping values off the stack that are incorrect. You should always have pairs of pushes and pops for the stack.

MyndFyre

Quote from: NicoQwertyu on November 17, 2004, 03:13 PM
Quote from: MyndFyre on November 17, 2004, 03:03 PM
Quote from: NicoQwertyu on November 17, 2004, 01:37 PM
After stepping through it in a debugger: my code executes, jumps to the correct address, does what I want it to, hits a "retn 0", then ends up somewhere else where it, according to the debugger, has an "access violation when reading [FFFFFFFF]".  How can I fix whatever's going wrong?  :-[

It's hitting a ret instruction?  Perhaps you need to use call rather than jmp in your code.

That wouldn't work for what I want it to do.  And it should hit a ret, shouldn't it?  The address I jump to is in the middle of a function.   :o

Sure it would.  You can call an address directly last I checked.

When CALL is used, a pointer to the next instruction in memory is saved (and code segment?) on the stack.  RET pops them off of the stack.  So, you're probably trying to read the instruction at 0xffffffff, because that was the value popped off the stack, and are subsequently getting an access violation.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

iago

When you do a call, it does this:
push return address;
jump location

When you do a return, it does:
pop return address->current location

You need to have a "call" before you can have a "ret", otherwise it has no idea where to return to.
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*



Skywing

Perhaps you might post your entire hook, where you are installing it (and what instructions you are patching in), and a disassembly of the target function in calc.exe.

NicoQwertyu

Quote from: Skywing on November 17, 2004, 04:42 PM
Perhaps you might post your entire hook, where you are installing it (and what instructions you are patching in), and a disassembly of the target function in calc.exe.




DLL to be injected:


#include "stdafx.h"
#include <windows.h>
#include <stdio.h>


extern "C" __declspec(dllexport) LRESULT CALLBACK DummieCallback(int nCode, WPARAM wParam, LPARAM lParam);


HWND hWnd = FindWindow(NULL, "Calculator");
char sBuffer[] = "test";

BOOL APIENTRY DllMain(HANDLE hModule, DWORD  dwReason, LPVOID lpReserved)
{
    return TRUE;
}



extern "C" __declspec(dllexport) LRESULT CALLBACK DummieCallback(int nCode, WPARAM wParam, LPARAM lParam)
{

///////////
//////////

MSG *msg = (MSG*)lParam;

if (nCode < 0)
{
return CallNextHookEx((HHOOK)0, nCode, wParam, lParam);
} else {

_asm
{
mov eax, offset sBuffer
push eax
mov ecx, 0x01004189
call ecx
}

MessageBeep(MB_OK);

return CallNextHookEx((HHOOK)0, nCode, wParam, lParam);
}



}


(Right now it's only purpose to put the text "Test" in whatever window the calulator uses to display it's stuff evertime calc.exe recieves a message)


Code that injects DLL:


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

int main()
{
HWND hWndProcess;
DWORD dwThreadId;
HMODULE hInjected;
HOOKPROC hDummieProc;

hWndProcess = FindWindow(NULL, "Calculator");
dwThreadId = GetWindowThreadProcessId(hWndProcess, NULL);

if (hWndProcess == 0 || dwThreadId == 0)
{
MessageBox(NULL, "Unable to gain thread id!", "ERROR", MB_OK);
return 0;
}

hInjected = LoadLibrary("testdll.dll");
hDummieProc = (HOOKPROC)GetProcAddress(hInjected, "_DummieCallback@12");

if (hInjected == NULL || hDummieProc == NULL)
{
MessageBox(NULL, "Unable to inject DLL!", "ERROR", MB_OK);
FreeLibrary(hInjected);
return 0;
}

SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC)hDummieProc, (HINSTANCE)hInjected, dwThreadId);
return 0;
}




Target function:

Quote

01004166   PUSH ESI
01004167   PUSH EDI
01004168   PUSH 193
0100416D   PUSH DWORD PTR SS:[ESP+10]
01004171   CALL DWORD PTR DS:[<&USER32.GetDlgItem>]

01004177   MOV ESI,EAX
01004179   PUSH DWORD PTR SS:[ESP+10]
0100417D   CALL DWORD PTR DS:[<&KERNEL32.lstrlenA>]

01004183   MOV EDI,EAX
01004185   PUSH DWORD PTR SS:[ESP+10]                  ; Push Text
01004189   PUSH ESI                                                ; <---- I jump in here (push hWnd)
0100418A   CALL DWORD PTR DS:[<&USER32.SetWindowTextA>]

01004190   PUSH ESI
01004191   CALL DWORD PTR DS:[<&USER32.SetFocus>]

01004197   PUSH EDI
01004198   PUSH EDI
01004199   PUSH 0B1
0100419E   PUSH ESI
0100419F   CALL DWORD PTR DS:[<&USER32.SendMessageA>]

010041A5   PUSH 1
010041A7   POP EAX
010041A8   POP EDI
010041A9   POP ESI

010041AA   RETN 8

Kp

Based on a cursory look, your hook just won't work at all the way you wrote it.  For one thing, you jump to an instruction which pushes esi, but you didn't set up esi first.  Therefore, the wrong window handle will be passed to SetWindowTextA.  The original function sets esi using GetDlgItem, but your jump bypasses that.  From the look of that function, you ought to be able to call the function from the beginning.
[19:20:23] (BotNet) <[vL]Kp> Any idiot can make a bot with CSB, and many do!

|