Ksbunker Advanced Cheater
Reputation: 0
Joined: 18 Oct 2006 Posts: 88
|
Posted: Fri Sep 21, 2007 3:18 am Post subject: [Tut] Making Minesweeper its own trainer |
|
|
Premise behind how we patch minesweeper to become its own trainer;
- Hardcode required strings in the .code section in your code cave
- Modify OEP to direct the new EP (Entry Point) located at the start on our codecave. (After the strings of course... otherwise it will stall upon executing having mistaken the for string array for actual instructions)
- Write the code responsible for creating a new thread (if required, use relevant API to load additional functions).
- Write a jump instruction directing program flow back to the OEP (Original EP).
- Write the code responsible for the actual thread (Make sure the third parameter of CreateThread that points to the procedure/routine).
Now that was the theory, here's the practical code.
| Code: | 01004B00: "CreateThread",0
01004B0D: "Thread created s"
01004B1D: "uccessfully",0
01004B29: "Loaded...",0
01004B33: "F5 was pressed.."
01004B43: ".",0
01004B45: 00
01004B46: PUSH ksbunker.010045E4 ; FileName = "KERNEL32.dll"<--NEW EP
01004B4B: CALL kernel32.LoadLibraryA ; LoadLibraryA
01004B50: PUSH ksbunker.01004B00 ; ProcNameOrOrdinal = "CreateThread"
01004B55: PUSH EAX ; hModule
01004B56: CALL kernel32.GetProcAddress ; GetProcAddress
01004B5B: PUSH 0 ; /
01004B5D: PUSH 0 ; |
01004B5F: PUSH 0 ; |
01004B61: PUSH ksbunker.01004B85 ; Thread Address
01004B66: PUSH 0 ; |
01004B68: PUSH 0 ; |
01004B6A: CALL EAX ; \CreateThread
01004B6C: PUSH 0 ; Style = MB_OK|MB_APPLMODAL
01004B6E: PUSH ksbunker.01004B29 ; Title = "Loaded..."
01004B73: PUSH ksbunker.01004B0D ; Text = "Thread created successfully"
01004B78: PUSH 0 ; hOwner = NULL
01004B7A: CALL USER32.MessageBoxA ; MessageBoxA
01004B7F: JMP ksbunker.01003E21 ; <-----------------JMP BACK TO OEP
01004B84: NOP ;
01004B85: PUSH 0A ; /Timeout = 10. ms <--Start of Thread--\
01004B87: CALL kernel32.Sleep ; \Sleep |
01004B8C: PUSH 74 ; /Key = VK_F5 |
01004B8E: CALL USER32.GetAsyncKeyState ; \GetAsyncKeyState |
01004B93: CMP EAX,0 ; ...Error? |
01004B96: JE SHORT ksbunker.01004B85 ; ...If yes, jump to start of thread----/
01004B98: MOV EAX,ksbunker.0100569F ; Move ENDOF mineboard address in EAX |
01004B9D: /CMP EAX,ksbunker.01005340 ; ...is eax, 01005340? <----------------|---\
01004BA2: |JE SHORT ksbunker.01004B85 ; ...if yes, jump to start of thread----/ |
01004BA4: |CMP BYTE PTR DS:[EAX],8F ; ...current byte in eax 8F? (mine) |
01004BA7: |JNZ SHORT ksbunker.01004BAC ; ...if not, dec counter, cont. loop----\ |
01004BA9: |MOV BYTE PTR DS:[EAX],41 ; ...if YES! Move 41 (no mine) into eax | |
01004BAC: |DEC EAX ; dec eax (eax=current address) <-------/ |
01004BAD: \JMP SHORT ksbunker.01004B9D ; jump to start of loop --------------------/ |
You will notice that LoadLibrary and GetProcess were used to dynamically load CreateThread(), but then I didn't dynamically load MessageBox(), Sleep() or GetAsyncKeyState(). I choose to get their function address from user32.dll and call the address of the function directly. IDEALLY, if you were going to distribute this file afterwards, you would dynamically load all of the API you create (i.e. if the API is not loaded via the IAT). Using the current approach, should I dynamically load, createthread, that will work on most/all computers, however come the sleep, messagebox and getasynckeystate functions, the code may fail on these, because the address of the functions varies depending on service pack, os, if you had modified kernel32.dll, etc...
The other thing to now is that in the memory of minesweeper, the board begins at address 1005340 and ends at 1005694 (Maximum size board). Typically, all these bytes are not required, because board size varies from easy, moderate and hard. However, I have harded the max size in this example, just incase I choose to make a custom board, it will work there too.
Regarding the loop, it cycles through each byte between the end of the board and start and searches for the mine byte, if it is found, it is replaced with a non-mine byte. It the current address is the starting address, it will exit the loop and jump back to the start of the thread.
Now. This is all well and good. But how does one change the Entry Point to point to your new code instead of the original EP. OK! No need to download any external programs.
Presuming you have made you codecave and all the code works fine, its time to direct the Entry Point to your NEW EP. Assuming your process is loaded;
View > Memory (Alt+M) >
A window will appear displaying the memory attributes and addresses of all currently running processes and services. Using the Address column as a guide, locate your process in memory (typically at 00400000), or in the case of the current example, its at 01000000, you will see;
| Code: | Address Size Section Contains
01000000 1000 PE Header
01001000 4000 .text Code, Imports
01005000 1000 .data Memory Data
01006000 1A000 .rsrc Resources |
Double Click the 'PE Header' Line. Scroll down untill you see the line labelled 'AddressOfEntryPoint = 3E21' [The original EntryPoint, in RVA that is 01003E21. Using the same logic to get the offset to our NEW EP, do;
Address of New EP = 01004B46
ImageBase = 01000000
EP-ImageBase = 4B46, modify the bytes of the 'AddressOfEntryPoint = 4B46', SAVE, and ViOLA!!!
Comments, Critism, Suggestions most welcome!
|
|