Thursday, July 16, 2009

TVProgramGuide -- developer's view - #2

This is a follow up of my previous post on developer's view on my TVProgramGuide application.

There were 2 APIs identified : InitIR and GetIRCode

The next step is to identify the return types, calling convention, parameter list and types of these two. Let me explain how I discovered them for one of those APIs (GetIRcode - the difficult one) by reverse-engineering their disassembly.

Disassembly of ThatDll!GetIRCode

10001190 83ec0c sub esp,0Ch
10001193 8d442400 lea eax,[esp]
10001197 53 push ebx
10001198 8d4c2408 lea ecx,[esp+8]
1000119c 33db xor ebx,ebx
1000119e 50 push eax
1000119f 51 push ecx
100011a0 c6442410c0 mov byte ptr [esp+10h],0C0h
100011a5 c644241102 mov byte ptr [esp+11h],2
100011aa 885c2412 mov byte ptr [esp+12h],bl
100011ae 885c2413 mov byte ptr [esp+13h],bl
100011b2 885c2414 mov byte ptr [esp+14h],bl
100011b6 885c2415 mov byte ptr [esp+15h],bl
100011ba c644241601 mov byte ptr [esp+16h],1
100011bf 885c2417 mov byte ptr [esp+17h],bl
100011c3 c744240c08000000 mov dword ptr [esp+0Ch],8
100011cb e870ffffff call ThatDll!SendVendorCmd (10001140)
100011d0 3bc3 cmp eax,ebx
100011d2 5b pop ebx
100011d3 8b542410 mov edx,dword ptr [esp+10h]
100011d7 750c jne ThatDll!GetIRCode+0x55 (100011e5)
100011d9 8a4c2404 mov cl,byte ptr [esp+4]
100011dd 880a mov byte ptr [edx],cl
100011df 83c40c add esp,0Ch
100011e2 c20400 ret 4
100011e5 c602ff mov byte ptr [edx],0FFh
100011e8 83c40c add esp,0Ch
100011eb c20400 ret 4

Calling convention:
An easy technique to identify the calling convention is to look for the 'ret' statement @25,28 (I would also advise to double check with the caller's next instruction disassembly to make sure he doesn't play with the stack pointer). In stdcall calling convention the callee is supposed to free the stack space for arguments. I think here we are debating only over stdcall and cdecl calling conventions. So, if the 'ret' statement has any value given as operand (no. of bytes to free up on stack), then the calling convention should be 'stdcall'. In most cases, DLLs are stdcalls -- and this observation ensures that for this dll.

Return type (and out params):
In this case, we had already discovered that the technical return type is an int (and was returning 0x0 on keypress and 0xff on no keypress). However, we are still lacking the keycode when a key was pressed. If you look at the epilogue of the function, there are two branchings (clearly two rets @25,28). Please note the "mov byte ptr [edx],0FFh" @26. This looks like an error case, when SendVendorCmd failed (@21). A close look at the diassembly (@18,21) reveals that this code flow occurs when the return value of SendVendorCmd is non-zero (!=ebx); it should also be noted that the return value of GetIRCode is the same as the return value of SendVendorCmd (note that there is no change in eax after the call to SendVendorCmd). If you look at the success path(@22,23), an out parameter of SendVendorCmd (@[esp+4]) is copied on to the address in edx (note the byte ptr mov -- the out param value is so an unsigned char).

Argument list and types:
We are almost done. The only missing piece is to figure out what is edx pointing to. This is a crucial and challenging part. Please bear with me. The statement 'mov edx, dword ptr[esp+10h]'@20, means that the address of the parameter is on the stack. The return statement denotes a 4 byte cleanup on the stack; so it is likely that the fucntion takes only one parameter and that is a pointer to a byte (unsigned char*). However, it is not clear if the [esp+10h] belongs to the local stack variable in this function or is really a argument pushed by the caller -- use of ebp might have been much clearer, but we don't have a choice here. Looking at the disassembly of SendVendorCmd (ret 8) tells me that it uses 8 bytes on stack for arguments. So after the call to SendVendorCmd, the esp will be less by 8 bytes. Now if you carefully account for all the push and pop instructions in this function before [esp+10h]@20, you would find out that the [esp+10h] is indeed pointing to [esp_0+4h] if esp_0 is the esp at the time of entry of the function. [esp+4h] at the entry point clearly skips the return address and lands on the first argument to the function.

And hence the function is 'int (__stdcall *ThatDll!GetIRCode)(unsigned char*)'

I believe I don't have to mention about the InitIR API. But that was pretty simple; the prototype turned out to be 'void (__stdcall *InitIR)(void)' :D.

Now, how to I use ths info to dynamically hook onto the existing TV tuner application is the only critical missing part. Stay tuned!

1 comment:

  1. Please post the rest.. Or could you make an application to control other media players with the remote like Media Player Classic and Winamp. That would be most useful..