inline ASM, error C2415: improper operand type

11/17/2011 13:45 cAddict#1
This is how the native function looks like:
Code:
006952E9 - 8B 44 24 04                - mov eax,[esp+04]
006952ED - 89 41 20                   - mov [ecx+20],eax
006952F0 - C2 0400                    - ret 0004
Now this is how my hook for this function looks like:
Code:
void Naked NewCooldown()
{
	__asm
	{
		MOV dwCooldown, [ESP+0x04]
		MOV [ECX+0x20], dwCooldown
		RET 4
	}
}
I would like to store value of [ESP+0x04] in DWORD variable 'dwCooldown' but i am getting an error:
Code:
error C2415: improper operand type
can I count on your help?
11/17/2011 14:20 link#2
Trying to access two memory addresses in one instruction is invalid.
Also, in 32-bit ret is just an alias for retn.

Code:
void Naked NewCooldown()
{
	__asm
	{
		MOV EAX, [ESP+0x04]
		MOV [dwCooldown],EAX
		MOV [ECX+0x20],EAX
		RETN 4
	}
}
11/17/2011 14:50 cAddict#3
thanks link, but now i've got another problem, omg.

Code:
char chCooldownInfo[0] = "Cooldown value: %d\n";
void Naked NewCooldown()
{
	__asm
	{
		MOV EAX, [ESP+0x04]
		MOV [dwCooldown], EAX
		MOV [ECX+0x20], EAX

		// trying to push EAX on stack as a variable for chCooldownInfo
		// EAX already hold the value so there is no need to copy dwCooldown on stack, right?
		PUSH EAX
		MOV EAX, OFFSET chCooldownInfo
		PUSH EAX
		CALL printf

		// clean up the stack
		POP EBX
		POP EBX

		// return
		RETN 4
	}
}
Code:
void CooldownHandler()
{
	char chCooldownInfo[] = "cooldown value: %d\n";

	__asm
	{
		MOV EAX, [dwCooldown]
		PUSH EAX
		MOV EAX, OFFSET chCooldownInfo
		PUSH EAX

		CALL printf

		POP EBX
		POP EBX
	}
}

void Naked NewCooldown()
{
	__asm
	{
		MOV EAX, [ESP+0x04]
		MOV [dwCooldown], EAX
		MOV [ECX+0x20], EAX
		CALL CooldownHandler
		RETN 4
	}
}
I've tried both ways, both fail.

What I want to do is to print to console value of dwCooldown everytime my Cooldown hook is being executed but this code crash my game client.

edit:
i am getting really confused about asm. now im getting another error on:
Code:
		MOV EAX, OFFSET chCooldownInfo
error C2415: improper operand type
while this is working perfectly fine:
Code:
#include "stdafx.h"
#include "stdio.h"
#include "process.h"

char chFormat[] = "%s %d\n";
char chValue[] = "value:";
int	 iValue = 652;


int main( void )
{
   __asm
   {
      mov  eax, [iValue]
      push eax
      mov  eax, offset chValue
      push eax
      mov  eax, offset chFormat
      push eax

      call dword ptr [printf]

      pop  ebx
      pop  ebx
      pop  ebx
   }

   system("pause");
}
what is going on? oO
11/17/2011 18:05 link#4
Cleaning the stack by overwriting a 'sensitive' register like ebx (it could still hold some value important to the caller) isn't the best way.
In case of calling a cdecl-function just increment esp by the amount of bytes you have pushed before and are meant as parameters (printf gets 2 dwords as params -> add esp,8).

Either define chCooldownInfo as a global variable and use "offset chCooldownInfo" or define it inside a function to make it exist on the stack as long as the function itself gets executed and use "lea eax,[chCooldownInfo]".
In the latter case chCooldownInfo is just a pseudo-label for sth like ebp-4, therefore its address has to be calculated, in the former chCooldownInfo is an absolute label, means "push offset chCooldownInfo" would be like "push 00400210h"

Try this:
Code:
void Naked NewCooldown()
{
	char chCooldownInfo[] = "Cooldown value: %d\n";
	__asm
	{
		MOV EAX, [ESP+0x04]
		MOV [dwCooldown], EAX
		MOV [ECX+0x20], EAX

		PUSH EAX
		LEA EAX,[chCooldownInfo]
		PUSH EAX
		CALL printf

		ADD ESP,4*2

		RETN 4
	}
}
EDIT:
ah, and as far as I recall you have to call API functions in this manner "call dword ptr [printf]" as no jump-table gets generated and printf is the address of an IAT-entry which holds the function's actual address.
11/17/2011 19:41 cAddict#5
great explanation, I really appreciate your help.

edit:
My hook is still crashing my game client just after 'printf' is being executed by now I got a point.
11/17/2011 21:48 link#6
oops.. having a naked function with neither prologue nor epilogue and using local variable doesn't make sense..
The prologue actually adjusts esp and makes room for the local variables, thus declaring the function as naked but trying to access local variables is erroneous, didn't think of it..

Code:
char chCooldownInfo[] = "Cooldown value: %d\n";

void Naked NewCooldown()
{
	__asm
	{
		MOV EAX, [ESP+0x04]
		MOV [dwCooldown], EAX
		MOV [ECX+0x20], EAX

		PUSH EAX
		PUSH OFSSET chCooldownInfo
		CALL dword ptr [printf]

		ADD ESP,4*2

		RETN 4
	}
}
or

Code:
void NewCooldown(int param)
{
	char chCooldownInfo[] = "Cooldown value: %d\n";
	__asm
	{
		MOV EAX, [ESP+0x04]
		MOV [dwCooldown], EAX
		MOV [ECX+0x20], EAX
	}
	printf(chCooldownInfo, dwCooldown);
}
hope this finally works...
11/17/2011 22:38 cAddict#7
thank you for another educating reply.


however, first example cause an error in my compiler:
Code:
error C2400: inline assembler syntax error in 'first operand'; found 'newline'

and second one cause an engine crash at offset 'NewCooldown+46':
Code:
NewCooldown   - 83 EC 18              - sub esp,18
NewCooldown+3 - A1 00B00010           - mov eax,[__security_cookie]
NewCooldown+8 - 33 C4                 - xor eax,esp
NewCooldown+A - 89 44 24 14           - mov [esp+14],eax
NewCooldown+E - A1 60510010           - mov eax,[`string']
NewCooldown+13 - 8B 0D 64510010       - mov ecx,[`string'+4]
NewCooldown+19 - 8B 15 68510010       - mov edx,[`string'+8]
NewCooldown+1F - 89 04 24             - mov [esp+esp],eax
NewCooldown+22 - A1 6C510010          - mov eax,[`string'+C]
NewCooldown+27 - 89 4C 24 04          - mov [esp+04],ecx
NewCooldown+2B - 8B 0D 70510010       - mov ecx,[`string'+10]
NewCooldown+31 - 89 54 24 08          - mov [esp+08],edx
NewCooldown+35 - 89 44 24 0C          - mov [esp+0C],eax
NewCooldown+39 - 89 4C 24 10          - mov [esp+10],ecx
NewCooldown+3D - 8B 44 24 04          - mov eax,[esp+04]
NewCooldown+41 - A3 A0B80010          - mov [dwCooldown],eax
NewCooldown+46 - 89 41 20             - mov [ecx+20],eax   // this is the place that cause a crash
NewCooldown+49 - 8B 15 A0B80010       - mov edx,[dwCooldown]
NewCooldown+4F - 52                   - push edx
NewCooldown+50 - 8D 44 24 04          - lea eax,[esp+04]
NewCooldown+54 - 50                   - push eax
NewCooldown+55 - FF 15 A8500010       - call dword ptr [_imp__printf]
NewCooldown+5B - 8B 4C 24 1C          - mov ecx,[esp+1C]
NewCooldown+5F - 83 C4 08             - add esp,08
NewCooldown+62 - 33 CC                - xor ecx,esp
NewCooldown+64 - E8 AD300000          - call __security_check_cookie
NewCooldown+69 - 83 C4 18             - add esp,18
NewCooldown+6C - C3                   - ret

this asm code looks strange to me and its even more confusing :)
maybe this code is erasing some important registers?



maybe I should tell you few words on how this native function works
Code:
006952E9 - 8B 44 24 04                - mov eax,[esp+04]
006952ED - 89 41 20                   - mov [ecx+20],eax
006952F0 - C2 0400                    - ret 0004

// eax = 1140735489, 1144036829, and so on.
eax contains something like a timestamp+skill charge+cooldown, so game will know how long the cooldown should last.

these values are different from the one I can get by GetTickCount but every time I use skill value is increased by same amount:
current timestamp + (skill charge time + skill cooldown time)

now, if I patch this function like this:
Code:
006952E9 - C7 41 20 01000000          - mov [ecx+20],00000001
006952F0 - C2 0400                    - ret 0004
then it works perfectly and I get no cooldown at all so I can spam teens/houndreds of skills in a second.

The problem is this 'plain stupid patching' method does not satisfy me anymore and I want to learn something more 'sufisticated' ;)


edit:
I have succeded to stop my game from getting a crash by 'PUSHAD/POPAD' - saving and restoring registers, so my code looks like this:
Code:
void Naked NewCooldown()
{
	__asm
	{
		MOV EAX, [ESP+0x04]
		MOV [ECX+0x20], EAX

		PUSH EAX
		MOV EAX, OFFSET info
		PUSH EAX

		PUSHAD
		CALL DWORD PTR [printf]
		POPAD

		ADD ESP, 0x08

		RETN 4
	}
}
but something must be wrong because instead of "cooldown value: %d" I get this:
Code:
ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(
~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý
(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~
ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ý(
~ý(~ý(~ý(~ý(~ý(~ý(~ý(~ÉĆ}ÉĆ}ÉĆ}ÉĆ}ÉĆ}ÉĆ}ÉĆ}ÉĆ}ÉĆ}ÉĆ}ÉĆ}ÉĆ}ÉĆ}