Ok, so I'm reversing a function (we'll call this function functionA) and here's what it generally looks like:
; introBlock
mov eax, RegCode
lea ecx, [eax+11h]
imul ecx, eax
; bblock1
mov eax, 85D858Bh
imul ecx
sar edx, 0Ah
mov eax, edx
shr eax, 1Fh
add eax, edx
imul eax, 7A69h
sub ecx, eax
imul ecx, 1ACFh
; bblock2
mov eax, 85DCB87Dh
imul ecx
add edx, ecx
sar edx, 0Eh
mov eax, edx
shr eax, 1Fh
add eax, edx
imul eax, 7A65h
sub ecx, eax
imul ecx, 1AD7h
And my C code:
/* Necessary stuff so it makes sense. */
typedef unsigned long long int QWORD;
typedef unsigned long int DWORD;
#define HIDWORD(x) ((DWORD)((x) >> 32))
int functionA(int ArgumentOne)
{
/* introBlock */
QWORD ecx = 0; DWORD edx = 0; DWORD eax = 0;
ecx = (ArgumentOne + 0x11) * ArgumentOne;
/* bblock1 */
edx = HIDWORD(0x85D858B * ecx) >> 0x0A;
eax = ((edx >> 0x1F) + edx) * 0x7A69;
ecx -= eax;
ecx *= 0x1ACF;
/* bblock2 */
edx = (HIDWORD(0x85DCB87D * ecx) + ecx) >> 0x0E;
eax = ((edx >> 0x1F) + edx) * 0x7A65;
ecx -= eax;
ecx *= 0x1AD7;
// ...
}
I've taken the liberty of splitting the assembly/C into their respective blocks, which I will label introBlock, bblock1, and bblock2.
Side-by-side, introBlock and bblock1 are identical in output. When we get to bblock2...
edx = (HIDWORD(0x85DCB87D * ecx) + ecx) >> 0x0E;
...it does not have the same output as this:
mov eax, 85DCB87Dh
imul ecx
add edx, ecx
sar edx, 0Eh
I narrowed the problem down to the imul line. The value the assembly puts on register edx when it does edx:eax = eax * ecx is not the same as what I get when I try to do the same with C. I can get the exact same lower dword, but the upper dword isn't the same.
Anybody care to poke at my work and tell me where I went wrong?
Oh, and if anyone would care to explain the concept behind signed and unsigned arithmetic (not just variables, but like, imul and mul are different -- how?) as I can't wrap my mind around their differences. Thanks sidoh!