Author | Message | Time |
---|---|---|
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... [code] 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 [/code] 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... [code] 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 [/code] 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... [code] 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 [/code] 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. | October 11, 2006, 11:58 PM |
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 [code] 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 } } [/code] my function pointer.. [code] typedef void (__fastcall *fpAddChat) (unsigned long format, unsigned long thing, char *buffer); [/code] 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. | October 12, 2006, 12:42 AM |
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. ;-) [code] 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; } [/code] print away! | October 12, 2006, 11:44 PM |
Arta | Nice work :) | October 13, 2006, 8:32 AM |