• Welcome to Valhalla Legends Archive.
 

Determining a functions arguments and how to call it

Started by warz, October 11, 2006, 06:58 PM

Previous topic - Next topic

warz

Looking at certain battle.snp functions in a debugger is interesting and intertaining, but it's difficult to determine how certain function arguments are passed, what the arguments are and how many of them there are. Specifically I'm trying to determine what arguments the battle net print text function takes, and how to determine if it's fastcall, or what. (how to pass the arguments to the function). I've been watching the function in my debugger, watching the registers changes and seeing which ones are used etc. I'm just trying to call this function, and print my own text to the channel chat window. I'll show you all what I'm lookin at here...

A call to the print text function, battle.190020A4, printing a person talking...

1901D987  |. 68 38C50319    PUSH battle.1903C538                     ;  ASCII "BeTa`Warz"
1901D98C  |. 8D85 FCFDFFFF  LEA EAX,DWORD PTR SS:[EBP-204]
1901D992  |. 50             PUSH EAX
1901D993  |. E8 283FFEFF    CALL <JMP.&storm.#501>
1901D998  |. A1 00DA0319    MOV EAX,DWORD PTR DS:[1903DA00]
1901D99D  |. 85C0           TEST EAX,EAX
1901D99F  |. 74 0E          JE SHORT battle.1901D9AF
1901D9A1  |. F605 D8D80319 >TEST BYTE PTR DS:[1903D8D8],0F
1901D9A8  |. BB 11000000    MOV EBX,11
1901D9AD  |. 74 05          JE SHORT battle.1901D9B4
1901D9AF  |> BB 10000000    MOV EBX,10
1901D9B4  |> 8D8D 7CFEFFFF  LEA ECX,DWORD PTR SS:[EBP-184]
1901D9BA  |. 51             PUSH ECX
1901D9BB  |. 0FB6D3         MOVZX EDX,BL
1901D9BE  |. 52             PUSH EDX
1901D9BF  |. 6A 3E          PUSH 3E
1901D9C1  |. 8D85 FCFDFFFF  LEA EAX,DWORD PTR SS:[EBP-204]
1901D9C7  |. 50             PUSH EAX
1901D9C8  |. 68 AB360319    PUSH battle.190336AB
1901D9CD  |. 6A 3C          PUSH 3C
1901D9CF  |. 6A 14          PUSH 14
1901D9D1  |. 8D8D 74FCFFFF  LEA ECX,DWORD PTR SS:[EBP-38C]
1901D9D7  |. 68 74640319    PUSH battle.19036474                     ;  ASCII "%c%c%s%s%c %c%s"
1901D9DC  |. 51             PUSH ECX
1901D9DD  |. E8 C246FEFF    CALL battle.190020A4


I don't think the call to that storm function is relevant, I only included all of that prior information because this is pushing my username, which is used by the print text function, I believe.

At the time of the call, prior to entering the print text function, the registers look like so...


EAX 0012EF1C ASCII "BeTa`Warz"
ECX 0012ED94
EDX 00000010
EBX 00000010
ESP 0012ED64
EBP 0012F120
ESI 77D5F39A USER32.SendMessageA
EDI 00000001
EIP 1901D9DD battle.1901D9DD


EAX is my username, obviously, that I think was passed by being push'd. ECX is 0012ED94, which looks like a NULL dword. EDX, and EBX are 10? This doesn't seem to be relevant to any lengths, or anything. It seems to be a constant value. The value at ESP is 94 ED 12 00. The value at EBP is 58 F2 12 00.  EDI is always 1.

The actual print text function looks like this...

190020A4  /$ 55             PUSH EBP
190020A5  |. 8BEC           MOV EBP,ESP
190020A7  |. 83EC 20        SUB ESP,20
190020AA  |. 56             PUSH ESI
190020AB  |. 8B75 08        MOV ESI,DWORD PTR SS:[EBP+8]
190020AE  |. 57             PUSH EDI
190020AF  |. 8D45 10        LEA EAX,DWORD PTR SS:[EBP+10]
190020B2  |. 50             PUSH EAX
190020B3  |. FF75 0C        PUSH DWORD PTR SS:[EBP+C]
190020B6  |. 8D45 E0        LEA EAX,DWORD PTR SS:[EBP-20]
190020B9  |. 50             PUSH EAX
190020BA  |. C745 E4 FFFFFF>MOV DWORD PTR SS:[EBP-1C],7FFFFFFF
190020C1  |. C745 EC 420000>MOV DWORD PTR SS:[EBP-14],42
190020C8  |. 8975 E8        MOV DWORD PTR SS:[EBP-18],ESI
190020CB  |. 8975 E0        MOV DWORD PTR SS:[EBP-20],ESI
190020CE  |. E8 B0290000    CALL battle.19004A83
190020D3  |. 83C4 0C        ADD ESP,0C
190020D6  |. 85F6           TEST ESI,ESI
190020D8  |. 8BF8           MOV EDI,EAX
190020DA  |. 74 1A          JE SHORT battle.190020F6
190020DC  |. FF4D E4        DEC DWORD PTR SS:[EBP-1C]
190020DF  |. 78 08          JS SHORT battle.190020E9
190020E1  |. 8B45 E0        MOV EAX,DWORD PTR SS:[EBP-20]
190020E4  |. C600 00        MOV BYTE PTR DS:[EAX],0
190020E7  |. EB 0D          JMP SHORT battle.190020F6
190020E9  |> 8D45 E0        LEA EAX,DWORD PTR SS:[EBP-20]
190020EC  |. 50             PUSH EAX
190020ED  |. 6A 00          PUSH 0
190020EF  |. E8 E8270000    CALL battle.190048DC
190020F4  |. 59             POP ECX
190020F5  |. 59             POP ECX
190020F6  |> 8BC7           MOV EAX,EDI
190020F8  |. 5F             POP EDI
190020F9  |. 5E             POP ESI
190020FA  |. C9             LEAVE
190020FB  \. C3             RETN


The only change in register values from the time of the call, to the first action in the function, at 190020A4, is the address in ESP. This changes to 0012ED60, and the value at that address is E2 D9 01 19.

So, there's the call to the function, the register values and the function itself, along with a description of what happens during the calling process.

If anyone wouldn't mind checkin this out, and maybe helpin me figure out how this function is called, that'd be awesome. I don't quite understand this process entirely, which is why I'm looking for some help.

warz

I should also mention, and show yall my function pointer, and call to this function. I've got most of the registers mimic'd, but it's crashing because I'm obviously not calling this correctly. It crashes in another battle.snp function. Anywho, here's my function pointer, and call.

My call

void GlobalClass::AddChat(char *buffer, unsigned long format) {
__asm {
pushad
}

const fpAddChat subAddChat = (fpAddChat)0x190020A4;

__asm {
mov ebx, 10h
mov edi, 1h
}
subAddChat(format, 0x10, buffer);

__asm {
popad
}
}


my function pointer..

typedef void (__fastcall *fpAddChat) (unsigned long format, unsigned long thing, char *buffer);


the unsigned long format variable is the address in ECX. All of the registers match the actual brood war call at the time of my call, except ESP, EBP, ESI and ofcourse EIP.

warz

Well, nevermind. After futher experimenting, and such, I found an interesting function that accepts the address of a struct containing the proper values needed to print most chat messages, if not all. Here's what I've managed to get working. It prints text to the battlenet channel chat window. If you want to figure out the other byte values to change the formatting (theres several formats, for each message type), then just check them out in a debugger. ;-)


struct structAddChannelText {
DWORD pointerToUsername;
DWORD toggleByte1;
DWORD toggleByte2;
DWORD pointerToMessage;
char username[24];
char message[255];
};

void AddChat(char *username, char *message);

void GlobalClass::AddChat(char *username, char *message) {
__asm {
pushad
}
DWORD functionAddr = 0x1901B480;
structAddChannelText *chantext = new structAddChannelText;

chantext->toggleByte1 = 0x00;
chantext->toggleByte2 = 0x05;
strcpy(chantext->username, username);
strcpy(chantext->message, message);
chantext->pointerToUsername = (DWORD)chantext->username;
chantext->pointerToMessage = (DWORD)chantext->message;


__asm {
mov edi, chantext
call functionAddr

popad
}
delete chantext;
}


print away!

Arta