-Analysing the Code
-Hooking BitBlt for Clean Screenshots.
Needed:
-ODBG
-BypassMe1
Step 1) Analysing
First open Example.exe normally to see what it does. It should open a window
showing "Waiting for Counter-Strike Source". After starting the Game it prints "Good Luck" and says "Time: x", x stands for a random number.
After x MS it tells us that it sucessfully saved a Screenshot in C:\picx.bmp.
After we now what it does we can start olly and open Example.exe.
Than we scroll down until we find our main body.
004118B0 > 55 PUSH EBP 004118B1 8BEC MOV EBP,ESP 004118B3 81EC D8010000 SUB ESP,1D8 004118B9 53 PUSH EBX 004118BA 56 PUSH ESI 004118BB 57 PUSH EDI 004118BC 8DBD 28FEFFFF LEA EDI,DWORD PTR SS:[EBP-1D8] 004118C2 B9 76000000 MOV ECX,76 004118C7 B8 CCCCCCCC MOV EAX,CCCCCCCC 004118CC F3:AB REP STOS DWORD PTR ES:[EDI] 004118CE A1 08704100 MOV EAX,DWORD PTR DS:[__security_cookie] 004118D3 33C5 XOR EAX,EBP 004118D5 8945 FC MOV DWORD PTR SS:[EBP-4],EAX 004118D8 6A 00 PUSH 0 004118DA E8 E1010000 CALL Example.time 004118DF 83C4 04 ADD ESP,4 004118E2 8BF4 MOV ESI,ESP 004118E4 50 PUSH EAX 004118E5 FF15 F0834100 CALL DWORD PTR DS:[<&MSVCR90D.srand>] ; MSVCR90D.srand 004118EB 83C4 04 ADD ESP,4 004118EE 3BF4 CMP ESI,ESP 004118F0 E8 8CF8FFFF CALL Example.00411181 004118F5 8BF4 MOV ESI,ESP 004118F7 68 64584100 PUSH OFFSET Example.??_C@_0CE@NBDDCKBH@W>; ASCII "Waiting for Counter-Strike Source " 004118FC FF15 F4834100 CALL DWORD PTR DS:[<&MSVCR90D.printf>] ; MSVCR90D.printf 00411902 83C4 04 ADD ESP,4 00411905 3BF4 CMP ESI,ESP 00411907 E8 75F8FFFF CALL Example.00411181 0041190C 8BF4 MOV ESI,ESP 0041190E 68 48584100 PUSH OFFSET Example.??_C@_0BG@LECJLHBI@C>; ASCII "Counter-Strike Source" 00411913 6A 00 PUSH 0 00411915 FF15 5C844100 CALL DWORD PTR DS:[<&USER32.FindWindowA>>; USER32.FindWindowA
Scroll down again until you find:
0041195F FF15 F8834100 CALL DWORD PTR DS:[<&MSVCR90D.rand>] ; MSVCR90D.rand 00411965 3BF4 CMP ESI,ESP 00411967 E8 15F8FFFF CALL Example.00411181 0041196C 99 CDQ 0041196D B9 60EA0000 MOV ECX,[COLOR="DarkOrange"]0EA60[/COLOR] 00411972 F7F9 IDIV ECX 00411974 81C2 10270000 ADD EDX,[COLOR="DarkOrange"]2710[/COLOR]
The range is from 10.000 up to 60.000. So it makes every 10-60 seconds 1 screeny.
(0EA60 = 60000MS, 2710 = 10000MS).
Scroll down again.
004119A6 50 PUSH EAX 004119A7 FF15 D4824100 CALL DWORD PTR DS:[<&KERNEL32.Sleep>] ; kernel32.Sleep 004119AD 3BF4 CMP ESI,ESP 004119AF E8 CDF7FFFF CALL Example.00411181 004119B4 8BF4 MOV ESI,ESP 004119B6 8B85 ECFEFFFF MOV EAX,DWORD PTR SS:[EBP-114] 004119BC 50 PUSH EAX 004119BD 68 1C584100 PUSH OFFSET Example.??_C@_0N@HBMLDDJC@C?>; ASCII "C:/pic%i.bmp" 004119C2 8D8D F8FEFFFF LEA ECX,DWORD PTR SS:[EBP-108] 004119C8 51 PUSH ECX 004119C9 FF15 FC834100 CALL DWORD PTR DS:[<&MSVCR90D.sprintf>] ; MSVCR90D.sprintf 004119CF 83C4 0C ADD ESP,0C 004119D2 3BF4 CMP ESI,ESP 004119D4 E8 A8F7FFFF CALL Example.00411181 004119D9 8BF4 MOV ESI,ESP 004119DB 8D85 F8FEFFFF LEA EAX,DWORD PTR SS:[EBP-108] 004119E1 50 PUSH EAX 004119E2 68 00584100 PUSH OFFSET Example.??_C@_0BF@GDEGMAHF@S>; ASCII "Screenshot taken %s " 004119E7 FF15 F4834100 CALL DWORD PTR DS:[<&MSVCR90D.printf>] ; MSVCR90D.printf 004119ED 83C4 08 ADD ESP,8 004119F0 3BF4 CMP ESI,ESP 004119F2 E8 8AF7FFFF CALL Example.00411181 004119F7 8D85 F8FEFFFF LEA EAX,DWORD PTR SS:[EBP-108] [COLOR="SandyBrown"]004119FD 50 PUSH EAX 004119FE 6A 00 PUSH 0 00411A00 E8 D7F6FFFF CALL Example.004110DC[/COLOR]
The important part is Orange. This is where we acutally call our Screenshot Function. (1 Param is The Handle (HWND_DESKTOP = 0), 2 Param is the Path stored in EAX)
Go To Expression 004110DC.
We should see this now:
004110DC E9 9F030000 JMP Example.SaveScreen
Seems to be right. Double click it to see functions adress. (JMP 00411480)
Now go to Expression 00411480.
We are in Our Screenshot function now (See the GetSystemMetrics).
00411480 > 55 PUSH EBP 00411481 8BEC MOV EBP,ESP 00411483 81EC 9C010000 SUB ESP,19C 00411489 53 PUSH EBX 0041148A 56 PUSH ESI 0041148B 57 PUSH EDI 0041148C 8DBD 64FEFFFF LEA EDI,DWORD PTR SS:[EBP-19C] 00411492 B9 67000000 MOV ECX,67 00411497 B8 CCCCCCCC MOV EAX,CCCCCCCC 0041149C F3:AB REP STOS DWORD PTR ES:[EDI] 0041149E 8BF4 MOV ESI,ESP 004114A0 6A 00 PUSH 0 004114A2 FF15 50844100 CALL DWORD PTR DS:[<&USER32.GetSystemMet>; USER32.GetSystemMetrics 004114A8 3BF4 CMP ESI,ESP 004114AA E8 D2FCFFFF CALL Example.00411181 004114AF 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX 004114B2 8BF4 MOV ESI,ESP 004114B4 6A 01 PUSH 1 004114B6 FF15 50844100 CALL DWORD PTR DS:[<&USER32.GetSystemMet>; USER32.GetSystemMetrics
Scroll down till we got the line
00411608 FF15 80824100 CALL DWORD PTR DS:[<&GDI32.BitBlt>] ; GDI32.BitBlt
Step 2) Idea
Before we start hooking now, we need an idea what we are doing next and how to bypass this. There are many methods of course but I want to show you the usual way to get clean Screenshots easily.
1. We Hook BitBlt
2. Everytime BitBlt is called we want the hack to active his "panic" mode and deactivate it after we got our clean Screenshot.
Step 3) Coding
First of all create a new empty DLL
Than we create our BitBlt typedef four detours
typedef BOOL (WINAPI* oBitBlt)( HDC, int, int,int,int,HDC,int,int, DWORD); oBitBlt pBitBlt;
bool WINAPI myBitBlt( HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, HDC hdcSrc, int nXSrc, int nYSrc, DWORD dwRop) { if(nWidth >= 320 && nHeight >= 320) { keybd_event(VK_END, 0, 0, 0); keybd_event(VK_END, 0, KEYEVENTF_KEYUP, 0); Sleep(100); bool ret = pBitBlt(hdcDest,nXDest,nYDest,nWidth,nHeight,hdcSrc,nXSrc,nYSrc,dwRop); keybd_event(VK_END, 0, 0, 0); keybd_event(VK_END, 0, KEYEVENTF_KEYUP, 0); return ret; } bool ret = pBitBlt(hdcDest,nXDest,nYDest,nWidth,nHeight,hdcSrc,nXSrc,nYSrc,dwRop); return ret; }
U see we check if the size is bigger than 320*320. Everything below wont be a screenshot. Than after the check we press the key with keybd_event(),
than we take our screenshot (clean now because we activatet hacks panic mode),and than right after the original BitBlt we reactivate the hacks features.
(The original idea of using panic key is from EyePatch).
And the Hook ofcourse :D
pBitBlt = (oBitBlt)DetourFunction((LPBYTE)DetourFindFunction("Gdi32.dll","BitBlt"), (LPBYTE)myBitBlt);
Comment