 |
Cheat Engine The Official Site of Cheat Engine
|
| View previous topic :: View next topic |
| Author |
Message |
deama1234 Master Cheater
Reputation: 3
Joined: 20 Dec 2014 Posts: 328
|
Posted: Thu Feb 05, 2015 4:11 pm Post subject: Make a beep in auto-assembly? |
|
|
Well, I tried to "call beep" but that just crashes it whenever I press the button which has the "call beep" bit in it.
This documentation is interesting, but confuses me, because "I don't know how to read it".
https://msdn.microsoft.com/en-us/library/windows/desktop/ms679277%28v=vs.85%29.aspx
there's no eax's or ecx's or general auto-assembly stuff I know, so...
|
|
| Back to top |
|
 |
SteveAndrew Master Cheater
Reputation: 30
Joined: 02 Sep 2012 Posts: 323
|
Posted: Fri Feb 06, 2015 5:24 am Post subject: Re: Make a beep in auto-assembly? |
|
|
Ok well there wont be any assembler stuff there as it's a c++ reference, but that doesn't mean it's not helpful. The best way to see what you need to do in assembler is by looking code that works with cheat engine and debugging it. It isn't always necessary though like in this case.
Since you mentioned eax and ecx rather than rax and rcx I'm answering this question as it relates to 32-bit assembler. 64-bit has only one calling convention and is a bit different (parameters are passed via registers, then the stack, rather than only the stack)
Firstly we have:
| Code: |
BOOL WINAPI Beep(
_In_ DWORD dwFreq,
_In_ DWORD dwDuration
);
|
We can see that the return value for kernel32.Beep is a boolean. BOOL type in x86 c++ is a 32-bit data type which is either true or false, 1 or 0. WINAPI is just a typedef for __stdcall. An stdcall calling convention means the callee (API/Function being called) is the one responsible for cleaning up the stack as we'll see in a bit.
The return value ends up in the eax register. The return value basically always will be written to eax before the API/Function cleans up the stack (if it's __stdcall) and returns. ("ret / retn")
You need to push the parameters into the stack in reverse order. So the first parameter "dwFreq" will be pushed last, while the last parameter "dwDuration" will be pushed first.
pseudo code:
| Code: |
push dwDuration
push dwFreq
call kernel32.Beep
.if eax == 1
Success
.elseif eax == 0
Failure
.endif
|
The example given is "Beep( 750, 300 );" A 750 hertz frequency for 300 milliseconds. So let's get that c++ code line written as auto assembler code instead.
It also mentions using the MessageBeep api instead so let's also do that one.
| Code: |
[enable]
alloc(BeepTest,1024)
label(BeepSucceeded)
label(BeepFailed)
label(MessageBeepSucceeded)
label(MessageBeepFailed)
label(BeepTestExit)
label(BeepReturnValue)
label(MessageBeepReturnValue)
registersymbol(BeepTest)
registersymbol(BeepReturnValue)
registersymbol(MessageBeepReturnValue)
createthread(BeepTest)
BeepTest:
push #300
push #750
call kernel32.Beep
test eax,eax
jne BeepSucceeded
jmp BeepFailed
BeepSucceeded:
mov [BeepReturnValue],eax
BeepFailed:
push FFFFFFFF
call user32.MessageBeep
test eax,eax
jne MessageBeepSucceeded
jmp MessageBeepFailed
MessageBeepSucceeded:
mov [MessageBeepReturnValue],eax
MessageBeepFailed:
BeepTestExit:
ret
BeepReturnValue:
dd 0
MessageBeepReturnValue:
dd 0
[disable]
dealloc(BeepTest)
unregistersymbol(BeepTest)
unregistersymbol(BeepReturnValue)
unregistersymbol(MessageBeepReturnValue)
|
Upon attaching to any 32-bit application, and enabling the script (after added to CT), you'll hear two beeps (Beep, then MessageBeep) if they were successful and it looks like this after you go to address "BeepTest"
In my case both succeeded and I heard both, with the return values equaling 1 / true. (success == true)
Lets go over some of the code:
| Code: |
push #300 //300 milliseconds
push #750 //750 hertz
call kernel32.Beep //calling the Beep api
test eax,eax //checking eax for zero
|
after the "test eax,eax" line: A je would be eax is equal to zero (unsuccessful), and a jne (as shown in the example) would be eax is a nonzero value. (successful)
I think your code is crashing likely because when the call to kernel32.Beep returns it's popping off those two parameters when you either haven't pushed them, or pushed them incorrectly.
Let's try a more complicated win32 api maybe a few combined just so you have this down solid.
Here I did something pretty pointless as CE can allocate all the memory we need, but I just wanted to demonstrate how you can use those microsoft c++ reference pages to get help at calling virtually any windows api in assembler or auto assembler!
This code upon being enabled, creates a thread that first allocates 1KB of memory, then if successful gets your logged in user's username and if successful, displays it in a message box. Once the message box is closed, or if getting the username failed the memory allocated initially is released and the thread then exits.
| Code: |
[enable]
alloc(AllocGetUsernameDeallocTest,1024)
label(DeallocAndExitTest)
label(ExitTest)
label(pManuallyAllocatedMemory)
label(pUsernameLength)
label(pCaption)
registersymbol(AllocGetUsernameDeallocTest)
registersymbol(pManuallyAllocatedMemory)
createthread(AllocGetUsernameDeallocTest)
AllocGetUsernameDeallocTest:
push 40 //PAGE_EXECUTE_READWRITE
push 1000 //MEM_COMMIT
push #1024 //1024 bytes
push 0 //optional, make it null
call kernel32.VirtualAlloc
test eax,eax
je ExitTest //jmp is followed if allocation failed
mov [pManuallyAllocatedMemory],eax
push pUsernameLength //buffer length at this point
push eax //[pManuallyAllocatedMemory]
call advapi32.GetUserNameA //A version / non unicode
test eax,eax
je DeallocAndExitTest //jmp is followed if getting username failed
//here pUsernameLength is now the size of string
//returned to [pManuallyAllocatedMemory]
push 30 //MB_ICONEXCLAMATION
push pCaption
push [pManuallyAllocatedMemory] //[] value because the value is a pointer
push 0 //HWND, null is fine
call user32.MessageBoxA
DeallocAndExitTest:
push 8000 //MEM_RELEASE
push 0 //must be zero if MEM_RELEASE
push [pManuallyAllocatedMemory] //pointer to memory to be free'd
call kernel32.VirtualFree
ExitTest:
ret
pManuallyAllocatedMemory:
dd 0
pUsernameLength:
dd #1024
pCaption:
db 'Username:',0
[disable]
dealloc(AllocGetUsernameDeallocTest)
unregistersymbol(AllocGetUsernameDeallocTest)
unregistersymbol(pManuallyAllocatedMemory)
|
References Used:
VirtualAlloc->https://msdn.microsoft.com/en-us/library/windows/desktop/aa366887(v=vs.85).aspx
GetUsernameA->https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).aspx
MessageBoxA->https://msdn.microsoft.com/en-us/library/windows/desktop/ms645505(v=vs.85).aspx
VirtualFree->https://msdn.microsoft.com/en-us/library/windows/desktop/aa366892(v=vs.85).aspx
After enabled:
After message box closed:
Of course you could've just used CE to allocate the memory used and you could've shortened it a bit. The point was though just to show more of an example than just Beep / MessageBeep!
So do you understand how to call Windows API's from auto assembler now?
_________________
|
|
| Back to top |
|
 |
deama1234 Master Cheater
Reputation: 3
Joined: 20 Dec 2014 Posts: 328
|
Posted: Fri Feb 06, 2015 10:36 am Post subject: |
|
|
Yes, it makes more sense now, thanks.
Though, what is this "registersymbol(BeepReturnValue)"?
EDIT: I got another question: can I create a thread in the middle of execution?
So...
Psudocode:
| Code: | sub [ebx+00000480],eax /*it runs this then goes to the beep
push #1000 *but how do I make it run this AND go past it?
push #150 *Kinda like creating a thread just to run the
call kernel32.Beep *beep. I tried doing this but it runs it when I
*/Enable the script... |
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You can download files in this forum
|
|