GNIREENIGNE Posted May 29, 2016 Posted May 29, 2016 Does anyone know of any good tutorials that show you how to properly call a function (e.g. satisfy all of the parameters of the call, stack allocation and cleanup etc.)? I've noticed a few items in some popular debuggers that might be used for this purpose, but I'm not sure about it. Thanks.
crystalboy Posted May 29, 2016 Posted May 29, 2016 The question in my opinion is not so much clear, give more details. Which functions do you need to call? Which programming language do you want to use? 1
GNIREENIGNE Posted May 29, 2016 Author Posted May 29, 2016 Thanks for replying. I am asking about calling functions in assembly x86 and x64. I know the calling conventions are different, but I'm not sure about the rest. Thanks, again.
crystalboy Posted May 29, 2016 Posted May 29, 2016 My best suggestion is to read Modern X86 Assembly Language Programming by Daniel Kusswurm. (you can find it on the web) It is a great book to clarify the concept that you miss. As i know no one did tutorials on that topic so the best. Hope it helps 1
GNIREENIGNE Posted May 29, 2016 Author Posted May 29, 2016 Thank you. I will certainly take a look at it.
kao Posted May 29, 2016 Posted May 29, 2016 That book isn't bad but in my opinion it doesn't explain calling conventions well enough. This CodeProject article sums it up rather nicely: http://www.codeproject.com/Articles/1388/Calling-Conventions-Demystified 1
GNIREENIGNE Posted May 30, 2016 Author Posted May 30, 2016 Thank you. I will read through that, for sure. If anyone has any tutorials for specifically calling functions using x32/x64dgb, immunity or olly etc., please let me know. Thanks!
GNIREENIGNE Posted May 31, 2016 Author Posted May 31, 2016 Just a quick update, for anyone that is interested and/or can provide some additional information on this topic... I skimmed through the book on modern x86 assembly, and, although very thorough, it doesn't actually provide what I am looking for. Additionally, the webpage that outlines the different calling conventions does just that - outlines the various calling conventions. Although helpful, it too does not actually provide the information that I need. I have scoured the web only to find various articles and videos explaining the stack and how stack data is stored and layered for various purposes, including calling parameters etc....most of which, are not strictly assembly examples, but examples for assembly to C, C to assembly et al.. There does not actually seem to be any tutorial, anywhere, that shows you how to call a function using strictly assembly, using a live, practical example via x32/64dbg, ollydbg, immunity or other. That said, hopefully someone can create one because I can't seem to figure this out. Thanks.
kao Posted May 31, 2016 Posted May 31, 2016 If you know how various calling conventions work, you have all the information you need. You know how to pass parameters, how to call the function, how the result is returned and how clean up stack. That's it, there's nothing else to be learned. So, where exactly are you stuck? Example program, big pictures and looong explanation of what you did and what's not working would certainly help. 2
GNIREENIGNE Posted May 31, 2016 Author Posted May 31, 2016 (edited) Thanks for responding, kao. I have a very basic understanding of what it entails, but how to properly apply it is the difficult part. I spent a great deal of time yesterday trying to call a function, using various different approaches, but I was really just guessing the entire time as far as what to push on to the stack and so forth. For example, I would set a breakpoint on a call that was getting executed constantly. I would examine the values for the various registers and try to mov/push those values back on to the stack (since I was trying to execute the call using my own, separate thread that was not part of the module). Everything that I tried did not work. I just need to understand how to determine what to do and in what order. If I can understand the 'what', then I can understand the 'how' and the 'why', it would really help. I can try again and provide more information with pictures and so forth, if you like. I appreciate any help on the matter. Thanks. EDIT: So, for yesterday's example, I used an SNES emulator (snesgt.exe v0.230 beta 6) to speed up the process, with Super Mario Kart (USA) rom. Here are the CRC/Hash values for the emulator and rom: EMULATOR: CRC32 - 9DFDB072 MD5 - 3A9D2E93B9C438B99813D3D403CD2B57 SHA-1 - 16263C9934A494E1223BB2CE6EE0F7621C6FAF10 ROM: CRC32 - CD80DB86 MD5 - 7F25CE5A283D902694C52FB1152FA61A SHA-1 - 47E103D8398CF5B7CBB42B95DF3A3C270691163B I used Cheat Engine 6.5.1 to inject my code, using the built-in createthread feature. I wrote a custom script for that (see below for one example). Attached is an image of the breakpoint. Here is an example of one of my attempts: [ENABLE] alloc(cave,248) createthread(cave) cave: sub esp,12 mov esi,0285A1D0 mov edi,0285FF08 mov ebx,0 mov ebp,68 call snesgt.exe+12D30 add esp,12 ret [DISABLE] dealloc(cave) Here is another example, of a failed attempt (I can provide many more): [ENABLE] alloc(cave,248) createthread(cave) cave: sub esp,4 mov ecx,051100A8 push ecx call snesgt.exe+12D30 pop ecx add esp,4 ret [DISABLE] dealloc(cave) Edited May 31, 2016 by GNIREENIGNE 1
kao Posted May 31, 2016 Posted May 31, 2016 (edited) I'm not using SNES emulators or CheatEngine, so I can't comment if you're using it correctly or not. And it would help a lot, if you could show disassembly of that function you're calling. But even without that I can tell you immediately: 1) based on the disassembly you provided, I am *guessing* that the software was written in Delphi/Pascal and functions use Borland's register calling convention. You can see that ECX register was used at the very start of function (snesgt.exe+1F170) and ECX was assigned right before call (snesgt.exe+1F19D). Your code doesn't do that. 2) what's the point of "sub esp, 12" and "add esp, 12" in your code? You're not using the stack and it looks like the function you're calling is not using it either. 3) you have some "magic" values in ESI/EDI registers. If the code you're calling doesn't use them, don't set them. If code is using them, they are very likely to change on each run, so you should find them in process memory somehow. And few general issues that may or may not be real issues, depending on CheatEngine's behavior: 1) thread procedures should end with "ret 4" (unless CheatEngine's injector is really forgiving). Reason - freshly created thread gets one parameter on stack, and it should clean it up: https://msdn.microsoft.com/en-us/library/windows/desktop/ms686736(v=vs.85).aspx 2) your code is messing up ebp, ebx, esi and edi registers. Again, unless CheatEngine is really forgiving, you code should never do that. All calling conventions require you to save most of the registers. EDIT: and how using cheatengine is relevant to calling function from Olly/Immunity/x64dbg? Edited May 31, 2016 by kao 2
GNIREENIGNE Posted May 31, 2016 Author Posted May 31, 2016 Thanks for replying, kao. When you say 'show dissassembly', what are you referring to, exactly? Attached is a screenshot of another break (showing the stack options), at the same location, but during a different session. I have also attached a screenshot of the full stack, using the esp+ parameters. I have tried, in previous attempts, to push and mov every value from the registers before calling, and popping them after the call, but that also didn't work. As far as ret4, I do not believe that is required with CE, as all of the examples that I have seen do not show them that way. I cannot confirm any of the other details regarding CE. I apologize for not understanding most of this. Thanks, again.
GNIREENIGNE Posted May 31, 2016 Author Posted May 31, 2016 (edited) 31 minutes ago, kao said: EDIT: and how using cheatengine is relevant to calling function from Olly/Immunity/x64dbg? It's not. It's was I use mostly these days, but any program will do. CE makes it a lot easier for code injection. Other than that, it really doesn't matter which program we use, as the idea is basically the same. Tell me your preference, and we can use that. EDIT: For that matter, we can use any example file to test on, as well. Whatever is easier. I appreciate you taking the time to help me. EDIT#2: Here are more screenshots (from x32dbg): Edited May 31, 2016 by GNIREENIGNE
kao Posted May 31, 2016 Posted May 31, 2016 OK, let's start learning with something extra simple. Attached is a very simple test executable. At address 401270 is a method which shows message box. Method takes no parameters, so the calling convention is not really important. It also doesn't use any variables from the process. Run the process and inject code that calls this method. Once you manage to do that, I'll create a new executable, making it more difficult each step. step1.zip 3
atom0s Posted May 31, 2016 Posted May 31, 2016 Given that ECX is being populated before the call, it makes it more likely to be __thiscall (class member call), where ECX is holding the object pointer and the call is to a class function. As long as you are giving the proper parameters, it should handle the call fine. Keep in mind if that call requires other internal bits to be constructed and such, those will need to be done as well. For example if you are calling a member function that internally tries to use a block of memory that isn't allocated yet, you are going to crash. Take this for example: .text:101E1643 push 0 ; char .text:101E1645 push 1 ; char .text:101E1647 push offset aMenuOlstat ; "menu olstat " .text:101E164C mov ecx, offset unk_105D8FB0 .text:101E1651 call sub_10155D20 There are 4 arguments to this __thiscall function. The first being the class object moved into ECX, then the others are pushed onto the stack. In C++ this would look like this: auto func = (int(__thiscall *)(void* pThis, const char*, char, char))sub_10155D20; In C++ I can call this function from an injected DLL doing this: auto argument1 = "menu olstat "; auto argument2 = 1; auto argument3 = 0; auto funcPointer = (DWORD)::GetModuleHandle("Game.dll") + 0x155D20; auto func = (int(__thiscall *)(void* pThis, const char*, char, char))funcPointer; auto funcThis = (LPVOID)((DWORD)::GetModuleHandle("Game.dll") + 0x5D8FB0); func(funcThis, argument1, argument2, argument3); In your Cheat Engine script, since you are injecting a thread, you don't need to have any type of prologue/epilogue code. You can just call the function directly with the proper arguments. In your first Cheat Engine post, it looks like you only have 1 argument to push (eax's value) then move the proper value into ECX and make the call. 2
atom0s Posted May 31, 2016 Posted May 31, 2016 Here is another example written in C++, this is a basic app that makes a class call to show a message: /** * __thiscall example by atom0s [atom0s@live.com] */ #include <Windows.h> /** * Basic Class Example */ class BasicClass { public: BasicClass(void) { } ~BasicClass(void) { } /** * Example call demonstrating the __thiscall convention. * * @param {bool} retValue The value for this function to return. * @param {const char*} msg The message to display. * @param {const char*} title The title of the message to display. * @returns {bool} User defined return from the first argument. */ bool ExampleCall(bool retValue, const char* msg, const char* title) { ::MessageBox(HWND_DESKTOP, msg, title, MB_OK); return retValue; } }; // Create an instance of our basic class.. // This is done outside of the main call to prevent stack usage. auto b = new BasicClass(); /** * Application entrypoint. * * @param {int} argc The number of arguments passed to this application. * @param {char* []} argv The arguments passed to this application at startup. */ int __cdecl main(int argc, char* argv[]) { UNREFERENCED_PARAMETER(argc); UNREFERENCED_PARAMETER(argv); while (true) { // Allow F1 to exit the loop.. if (::GetAsyncKeyState(VK_F1) & 1) break; // Allow F2 to show our message.. if (::GetAsyncKeyState(VK_F2) & 1) b->ExampleCall(true, "Hello world!", "Title here!"); // Sleep to not kill the CPU.. ::Sleep(10); } // Cleanup our class object.. if (b) delete b; b = nullptr; return ERROR_SUCCESS; } In OllyDbg/IDA you can see how this is called when F2 is pressed here: .text:004010F1 loc_4010F1: ; CODE XREF: sub_4010D0+1D�j .text:004010F1 push 71h ; vKey .text:004010F3 call ds:GetAsyncKeyState .text:004010F9 movsx edx, ax .text:004010FC and edx, 1 .text:004010FF jz short loc_401118 .text:00401101 push offset Caption ; "Title here!" .text:00401106 push offset Text ; "Hello world!" .text:0040110B push 1 ; char .text:0040110D mov ecx, dword_4033F4 .text:00401113 call sub_4010A0 In my test app, I have the function take 3 arguments, a boolean, and two strings. Compiled this requires ECX be filled with the class object. Running the application we can force call this function with our own parameters via Cheat Engine's autoassembler like this: [ENABLE] alloc(cave, 1024) alloc(appname, 1024) alloc(str1, 1024) alloc(str2, 1024) createthread(cave) appname: db 'ClassCallExample.exe',0 str1: db 'This is my custom message!',0 str2: db 'Title',0 cave: push appname // push the application name call GetModuleHandleA // obtain the applications base address mov edx, eax // store this base for call usage add eax, 33F4 // offset the base to the 'this' object for the class call add edx, 10A0 // offset the base to the function call push str2 // push the title push str1 // push the message push 1 // push the return value (bool argument) mov ecx, [eax] // obtain the 'this' object for the function call call edx // call the function ret // return [DISABLE] dealloc(cave) dealloc(appname) dealloc(str1) dealloc(str2) Sadly, Cheat Engine's autoassembler has some limitations on how it can handle strings within opcodes, so we can't do simple things like "call "ClassCallExample.exe" + 10A0" to make the code cleaner. This is much easier to do in another language though like C++ if you inject a DLL etc. since you can do direct casting and so on. ClassCallExample.rar 2
GNIREENIGNE Posted May 31, 2016 Author Posted May 31, 2016 Thanks, guys. Some of this is over my head, but some of it actually makes sense. Please give me some time to go over everything and I will report back as soon as I can. By the way, atom0s, getting the base address of the module is not necessary with CE if module addressing is viable for the target process, right? Thanks.
GNIREENIGNE Posted May 31, 2016 Author Posted May 31, 2016 (edited) 2 hours ago, kao said: OK, let's start learning with something extra simple. Alright, so I've managed to call that function easily enough. Thanks! Here is my solution, using CE: [ENABLE] alloc(cave,48) createthread(cave) cave: push 0 push 402021 push 402014 push 0 call 4012d2 ret [DISABLE] EDIT: atom0s: I cannot seem to run ClassCallExample.exe. I receive the following error (see attachment). I tried running in compatibility mode for WinXP SP3 and as admin, but that didn't work. I also tried downloading Visual C++ 2015 redis (x64)...I could not find an (x86) version - but that didn't work, either. I actually have the dll on my computer, so I copied it to the temporary folder where the exe is being stored and tried again...but now I'm receiving another error saying that the application was unable to start correctly (0xc0000007b). By the way, I keep trying to call the function from the SNES emulator, but I'm still doing something wrong. Here is an example of my latest attempt: [ENABLE] alloc(cave,248) createthread(cave) cave: push eax push ecx mov eax,6 mov ecx,04FC00A8 call snesgt.exe+12D30 pop ecx pop eax ret [DISABLE] dealloc(cave) Edited May 31, 2016 by GNIREENIGNE
kao Posted May 31, 2016 Posted May 31, 2016 That's not exactly right. You're not calling that function, you're copying the entire code of that function. Feel the difference? Spoiler You would need only 2 lines in your cave - "call 401270" and "ret" Here's step 2. Now function at address 401270 uses stdcall calling convention and takes some parameters. Your task it to call it with correct parameters, so that message box is shown. step2.zip 1
GNIREENIGNE Posted May 31, 2016 Author Posted May 31, 2016 Oh...I see now! Thanks! By the way, I solved the SNES emulator call (yay): [ENABLE] alloc(cave,248) createthread(cave) cave: push eax mov ecx,[snesgt.exe+115110] call snesgt.exe+12D30 pop eax ret [DISABLE] I will work on step2 when I get back from breakfast. Thanks, everyone!
GNIREENIGNE Posted May 31, 2016 Author Posted May 31, 2016 5 hours ago, kao said: Here's step 2. Now function at address 401270 uses stdcall calling convention and takes some parameters. Your task it to call it with correct parameters, so that message box is shown. These tutorials are really neat, kao. Thanks for helping me with this. Solving step2 only required me to change 1 byte from my first solution: [ENABLE] alloc(cave,48) createthread(cave) cave: push 0 push 402021 push 402014 push 0 call 4012DE ret [DISABLE] It works. I hope it's right.
atom0s Posted May 31, 2016 Posted May 31, 2016 7 hours ago, GNIREENIGNE said: atom0s: I cannot seem to run ClassCallExample.exe. I receive the following error (see attachment). I tried running in compatibility mode for WinXP SP3 and as admin, but that didn't work. I also tried downloading Visual C++ 2015 redis (x64)...I could not find an (x86) version - but that didn't work, either. I actually have the dll on my computer, so I copied it to the temporary folder where the exe is being stored and tried again...but now I'm receiving another error saying that the application was unable to start correctly (0xc0000007b). That means you are missing the runtime for it. It uses Visual Studio 2015 (C++) which you can snag the runtime for here: https://www.microsoft.com/en-us/download/details.aspx?id=51682 (This is done in 32bit so you only need the 32bit version (x86) but you can install both for any future app you run into that uses it.) 1
atom0s Posted May 31, 2016 Posted May 31, 2016 7 hours ago, GNIREENIGNE said: Thanks, guys. Some of this is over my head, but some of it actually makes sense. Please give me some time to go over everything and I will report back as soon as I can. By the way, atom0s, getting the base address of the module is not necessary with CE if module addressing is viable for the target process, right? Thanks. Supposed to be that way but my CE does not seem to like me using the module name(s) in autoassembler scripts. May just need to update it since I haven't in a while. 1
GNIREENIGNE Posted May 31, 2016 Author Posted May 31, 2016 19 minutes ago, atom0s said: That means you are missing the runtime for it. It uses Visual Studio 2015 (C++) which you can snag the runtime for here: https://www.microsoft.com/en-us/download/details.aspx?id=51682 That fixed it. Thanks! I actually visited that site earlier, but quickly closed it because I thought it was a redirect for windows 10. I will take a look at your example later. I will report back. Thanks, again. Regarding the module addressing in AA scripts...yeah, you may need to update. The way you showed it in your example helped me learn something new, though.
GNIREENIGNE Posted May 31, 2016 Author Posted May 31, 2016 (edited) [ENABLE] alloc(cave,48) createthread(cave) cave: push classcallexample.exe+2190 push classcallexample.exe+219c push 1 mov ecx,[classcallexample.exe+33f4] call classcallexample.exe+10a0 ret [DISABLE] Here is my solution. It seems to work! Edited May 31, 2016 by GNIREENIGNE
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now