Ron's guide to Assembly is your bible, especially
this page.
I'm at home increasingly less often, but when I am, I can try to lend you a hand. It's not the code itself that's complicated -- any idiot can port it back to C, it's the fact that you've got to figure out from a series of calculations what's going on.
Prime example:
.text:004014AC cmp [esi], bl ; BL is 0 -- we're looking for a null char
.text:004014AE mov eax, esi
.text:004014B0 jz short loc_4014B7 ; if(*esi == bl) { jmp loc_4014B7; }
.text:004014B2
.text:004014B2 loc_4014B2: ; CODE XREF: CheckRevision+45j
.text:004014B2 inc eax ; We're searching for the first null character on the stack
.text:004014B2 ;
.text:004014B2 ; C++:
.text:004014B2 ; while(*(++eax) != (int)0)
.text:004014B3 cmp [eax], bl
.text:004014B5 jnz short loc_4014B2 ;
.text:004014B5 ; Eventually, we've ended up with the length of the EXE string
.text:004014B5 ; I don't have a clue why they don't just take this argument in
.text:004014B7
.text:004014B7 loc_4014B7: ; CODE XREF: CheckRevision+40j
.text:004014B7 sub eax, esi
.text:004014B9 push eax ; dwBytes
.text:004014BA mov [esp+1A4h+var_194], eax
.text:004014BE call HeapAllocWrapper ; This alloc's a chunk of memory the size of the EXE path
From my comments, you should be able to tell pretty easily what it does, but if it weren't commented it'd be tough. Keep in mind that they don't actually get the three paths as arguments, but skip to -0x0C on the stack, so this is actually reading from the pointer on the stack, not the argument. Not that it makes that much of a difference, but it's another complication you should be aware of.
int16 bl = 0;
if(*esi = bl)
{
jump nullExePath;
}
else
{
intptr32 &eax = esi;
do
{
&eax++;
} while(*eax != 0)
eax -= esi;
*(&var+194+0x1A4) = eax; // this is obviously not going to work, but you get the idea
eax = HeapAllocWrapper(eax);
// ...
}
Basically, it's calling strlen on EXE Path. I'm willing to bet var_194 is the EXE statstring, but I don't know.