Results 1 to 2 of 2
  1. #1
    Hell_Demon's Avatar
    Join Date
    Mar 2008
    Gender
    male
    Location
    I love causing havoc
    Posts
    3,976
    Reputation
    343
    Thanks
    4,320
    My Mood
    Cheeky

    [Concept&Code]Get bone positions[MW2]

    ~ This is also posted in the MW2 source code section ~
    Part 1 - some basic stuff you need to know about pointers to structures
    Code:
    #include <windows.h>
    #include <iostream>
    
    struct LOLSTRUCT
    {
    	int a; //0x0
    	int b; //0x4
    	char c[24]; //0x8
    	float d; //0x20
    }; //size = 0x24
    
    LOLSTRUCT WTF[5]; //Array of LOLSTRUCTS
    LOLSTRUCT *lolptr = &WTF[0]; //pointer to LOLSTRUCT array
    
    int main()
    {
    	printf("WTF %x \n\nLOLPTR: %x\n[0] %x\n[1] %x\n[2] %x\n", WTF, lolptr, &lolptr[0], &lolptr[1], &lolptr[2]);
    	Sleep(10000);
    	return 1;
    }
    if we run that it will say something along the lines of
    Quote Originally Posted by retardapp
    WTF 403378

    LOLPTR 403378
    [0] 403378
    [1] 40339C
    [2] 4033C0
    Now, let's say LOLSTRUCT is the retarded struct of a retarded program written by a retard(/me)
    We are interested in c, since that contains the name of the player.
    but oh f*ck, we don't have the original struct... No worries tho, we have ollydbg skills =)

    Code:
    00401000 >/$ 68 C0334000    PUSH StructTe.004033C0                   ; /<%x> = 4033C0
    00401005  |. 68 9C334000    PUSH StructTe.0040339C                   ; |<%x> = 40339C
    0040100A  |. 68 78334000    PUSH OFFSET StructTe.WTF                 ; |<%x> = 403378
    0040100F  |. 68 78334000    PUSH OFFSET StructTe.WTF                 ; |<%x> = 403378
    00401014  |. 68 78334000    PUSH OFFSET StructTe.WTF                 ; |<%x> = 403378
    00401019  |. 68 04214000    PUSH OFFSET StructTe.??_C@_0CK@JGACCNEP@>; |format = "WTF %x 
    
    LOLPTR: %x
    [0] %x
    [1] %x
    [2] %x
    "
    0040101E  |. FF15 9C204000  CALL DWORD PTR DS:[<&MSVCR90.printf>]    ; \printf
    00401024  |. 83C4 18        ADD ESP,18
    00401027  |. 68 10270000    PUSH 2710                                ; /Timeout = 10000. ms
    0040102C  |. FF15 00204000  CALL DWORD PTR DS:[<&KERNEL32.Sleep>]    ; \Sleep
    00401032  |. B8 01000000    MOV EAX,1
    00401037  \. C3             RETN
    Yay!! We found the addies of the struct(403378, 40339C, 4033C0), but we are lazy and don't want to have to use hardcoded addies for all, so what we can do now is:
    A. Find the size of the struct, and go from there.
    B. Rebuild the struct(structbuilder is a great tool for this), partially or full, and go from there.

    A would look like:
    Code:
    DWORD *GetRetardPtr(int index)
    {
        return (DWORD*)0x403378 + (0x24*index);
    }
    Then you could use assembly to access it's members.

    B would look like:
    Code:
    struct LOLREBUILDED
    {
            char unknown000[8];
        char name[24];
            char unknown001[4];
    };
    
    LOLREBUILDED *ptr = (LOLREBUILDED*)0x403378;
    ptr[index].name = "PEDOWALDO=D";
    In my opinion, B is WAY more attractive, since we can just use it like a normal struct, and it's way easier to access members.

    So remember: [u]If the size of your struct is correct you can access each part of the array by specifying it's index[u]

    Part 2 - The real deal =)
    I'll be using the AlterIW version of MW2 since that's probably what most of you will be using, it works the exact same for 1.1.195!

    In order to get a bone's position you first need to have an entity to get the bone from.
    So lets find the CEntity, the string we'll be looking for is "%s is dead", the offset is -0x27(which is a direct offset, so scroll up once to see it in it's instruction):

    Code:
    00409041  |. 68 84527100    PUSH iw4mp_AL.00715284                   ; ASCII "%s is dead"
    0x00409041-0x27 = 0x0040901A
    Scroll up once and you'll have this instruction selected:
    Code:
    00409018  |. 81C6 787A8F00  ADD ESI,iw4mp_AL.008F7A78
    So the entity array is located at 0x008F7A78, so control+g there and 'Find references to selected command', pick a random one from the list of references(I took the first one).
    Code:
    0040246F  |. 69F6 04020000  IMUL ESI,ESI,204
    00402475  |. 81C6 787A8F00  ADD ESI,iw4mp_AL.008F7A78
    What happens is the index of the entity is placed in ESI, then ESI is multiplied by 0x204 and then stored in ESI, and then they add the base address of the array to it.

    0x204... IS THE SIZE OF CEntity STRUCT!
    Since we won't be doing a whole lot more with CEntity then getting bone positions, we can just declare it like this:
    Code:
    struct CEntity
    {
        char unknown[516]; //0x0
    }; //size = 0x204
    Now we can get an Entity by it's index like this:
    Code:
    CEntity *pEntities = (CEntity*)0x008F7A78;
    for(int i=0;i<18;i++)
    {
    	CEntity cEnt = pEntities[i];
    	//do stuff with cEnt here.
    }
    Since we're able to get entities now, let's look for "j_head", which is the 'tag'(bone) that is located inside their head(duh ^^)
    Search for all referenced text strings -> "j_head", there are two references to "j_head", here is the first one:
    Code:
    0045E92A  |. 68 EC336F00    PUSH iw4mp_AL.006F33EC                   ; push "j_head" onto stack
    0045E92F  |. 66:A3 86A7AF01 MOV WORD PTR DS:[1AFA786],AX		   ; move the id of the tag(j_head) into 1AFA786
    0045E935  |. E8 9634FFFF    CALL iw4mp_AL.00451DD0			   ; Call registertag
    The addy it gets mov'd into is always 2 bytes diff, which means tag IDs are probably of the type short.

    Here's the start of the same function:
    Code:
    0045E8F0  /$ 68 7C4A6F00    PUSH iw4mp_AL.006F4A7C
    0045E8F5  |. E8 D634FFFF    CALL iw4mp_AL.00451DD0
    0045E8FA  |. 68 244C7200    PUSH iw4mp_AL.00724C24                   ;  ASCII "active"
    0045E8FF  |. 66:A3 80A7AF01 MOV WORD PTR DS:[1AFA780],AX
    1AFA780 is the first registered tag, 1AFA786 is j_head
    1AFA786-1AFA780=6
    6/2 = 3
    so j_head probably has id 3.

    All that is left now is getting tag positions, let's do a string search for GetTagPos.
    "AimAssist_GetTagPos: Cannot find tag [%s] on entity %i." doesn't look very promising
    "AimTarget_GetTagPos: Cannot find tag [%s] on entity %i." however does!

    Code:
    005713A5  |. 68 00BC7000    PUSH iw4mp_AL.0070BC00                   ;  ASCII "AimTarget_GetTagPos: Cannot find tag [%s] on entity
    "
    Fuck yeah!


    Code:
    00571370  |. A1 D80B7F00    MOV EAX,DWORD PTR DS:[7F0BD8]
    00571375  |. 8B8E DC000000  MOV ECX,DWORD PTR DS:[ESI+DC]
    0057137B  |. 53             PUSH EBX
    0057137C  |. 0FB71D 86A7AF0>MOVZX EBX,WORD PTR DS:[1AFA786]		; "j_head" pushed onto stack
    00571383  |. 50             PUSH EAX
    00571384  |. 51             PUSH ECX
    00571385  |. E8 A65DEEFF    CALL iw4mp_AL.00457130
    0057138A  |. 8D5424 14      LEA EDX,DWORD PTR SS:[ESP+14]
    0057138E  |. 52             PUSH EDX
    0057138F  |. 53             PUSH EBX
    00571390  |. 50             PUSH EAX
    00571391  |. 56             PUSH ESI
    00571392  |. E8 6928ECFF    CALL iw4mp_AL.00433C00			; GetTagPos!
    00571397  |. 83C4 18        ADD ESP,18
    0057139A  |. 85C0           TEST EAX,EAX				; ^ Because EAX is tested, and GetTagPos will return true if it finds the tag
    0057139C  |. 75 16          JNZ SHORT iw4mp_AL.005713B4			; ^ if not, it will go to 'Cannot find tag' down below!
    0057139E  |. 53             PUSH EBX
    0057139F  |. E8 DC72EFFF    CALL iw4mp_AL.00468680
    005713A4  |. 50             PUSH EAX
    005713A5  |. 68 00BC7000    PUSH iw4mp_AL.0070BC00                   ;  ASCII "AimTarget_GetTagPos: Cannot find tag [%s] on entity
    "
    So we have GetTagPos now: 0x00433C00.
    This is what the function looks like:
    Code:
    int GetTagPos( CEntity* pEntity, void *pTagPointer, int TagID, float *vOrigin )
    Hmm... We have the entity, and the tagid, and vOrigin is where the origin will be stored if the tag is found, so all that's left is TagPointer...
    TagPointer is the 2nd argument of GetTagPos, arguments are pushed in reverse order which means EAX contains the tag pointer.
    Now what do we know... 00457130 is GetTagPointer! it's return value is stored in EAX and pushed onto the stack for usage in GetTagPos!
    GetTagPointer looks like this:
    Code:
    void *GetTagPointer(int ClientNumber)
    Only 1 argument, so the last thing pushed onto the stack is ClientNumber

    Code:
    00571375  |. 8B8E DC000000  MOV ECX,DWORD PTR DS:[ESI+DC] ; ESI+0xDC, so 0xDC is the offset to the client number.
    0057137B  |. 53             PUSH EBX
    0057137C  |. 0FB71D 86A7AF0>MOVZX EBX,WORD PTR DS:[1AFA786]		; "j_head" pushed onto stack
    00571383  |. 50             PUSH EAX
    00571384  |. 51             PUSH ECX		;ClientNumber
    00571385  |. E8 A65DEEFF    CALL iw4mp_AL.00457130
    And ESI appears to be the CEntity pointer, which is pushed last for GetTagPos(since it's the first argument)

    Now we have everything we need to get the bone position!

    Code:
    #define TAG_HEAD 0x3
    int (*pGetTagPos)( CEntity* pEntity, void *pTagPointer, int TagID, float *vOrigin ) = (int (__cdecl *)(CEntity*, void*, int, float*))0x00433C00;
    void *(*pGetTagPointer)(int ClientNumber) = (void *(__cdecl *)(int))0x00457130;
    
    
    void GetHeadPos(CEntity* pEnt, float *pOrigin)
    {
        D3DXVECTOR3 TagPosition;
        void* pTagPointer = GetTagPointer(pEnt->ClientNumber);
        pGetTagPos(pEnt, pTagPointer, TAG_HEAD, pOrigin);
    }
    To use the above code we'll have to change our CEntity struct a bit:
    Code:
    struct CEntity
    {
        char Unknown000[220]; //0x0
        int ClientNumber; //0xDC
        int iEntityType; //0xE0
        char Unknown001[288]; //0xE4
    };
    You'll probably notice we now have ClientNumber and iEntityType in there(which is checked against 1 in the 'AimTarget_GetTagPos' function to see if the Entity is a human)

    Finally, use GetHeadPos like this:
    Code:
    CEntity *pEntities = (CEntity*)0x008F7A78;
    D3DXVECTOR3 HeadPos;
    for(int i=0;i<18;i++)
    {
        if(pEntities[i].iEntityType != 1) continue; //if not human skip it
        GetHeadPos(&pEntities[i], &HeadPos);
        //Do whatever you want with head position here
    }
    I hope you guys have learned something from this, since I spent nearly 2 and a half hours on writing it >.>

    Credits:
    Hell_Demon - Writing all this crap up
    Melodia - Wanted me to write this all up for her ^^

    Have fun
    ~ Hell
    Ah we-a blaze the fyah, make it bun dem!

  2. The Following 5 Users Say Thank You to Hell_Demon For This Useful Post:

    'Bruno (06-18-2010),Cosmo_ (05-09-2015),falzarex (06-18-2010),Melodia (06-19-2010),schim (06-18-2010)

  3. #2
    schim's Avatar
    Join Date
    May 2010
    Gender
    male
    Location
    My chair
    Posts
    367
    Reputation
    10
    Thanks
    114
    My Mood
    Twisted
    Wow, nice coding :O
    *Is scraping the rust from his ollyskillz*

Similar Threads

  1. [Concept&Code]Get bone positions
    By Hell_Demon in forum Call of Duty Modern Warfare 2 Coding / Programming / Source Code
    Replies: 5
    Last Post: 06-18-2010, 03:55 AM
  2. [Tutorial] how to get unbanned from mw2 (working 100%)
    By zsniprx in forum Call of Duty Modern Warfare 2 Tutorials
    Replies: 32
    Last Post: 05-08-2010, 02:48 AM
  3. How to get unbanned from MW2.
    By eliteop in forum Call of Duty Modern Warfare 2 Discussions
    Replies: 90
    Last Post: 02-27-2010, 08:22 PM
  4. thoery to get unbanned from mw2
    By zsniprx in forum Call of Duty Modern Warfare 2 Discussions
    Replies: 24
    Last Post: 02-21-2010, 08:41 AM
  5. Demonoid invite codes! Get em quick!
    By Synns in forum General
    Replies: 5
    Last Post: 09-06-2007, 01:12 AM