I was messing around with the AoE2HD binary for a little while, so I decided to share some of my findings.
Note: I disabled ASLR, as I couldnt be arsed with calculating the offsets, so all the function addresses have 0x400000 base.
Code:struct Player; struct Price; struct Resources; struct Unit; struct MainClass; struct UIMain; struct UITextElement; struct GameData; struct ObjectManager; struct UnitData; struct TargetPtr; struct TargetData; struct BuildEventArgs; struct ChatLog; struct DrawingData; MainClass* mainClassPointer = *(MainClass**)0x0B7A174; ChatLog* chatLogPointer = *(ChatLog**)0x00B7A0E0; struct MainClass { /*0x0000*/ char unk_0000[0x21C]; /*0x021C*/ GameData* gameMain; /*0x0220*/ char unk_0220[0x1384]; /*0x15A4*/ UIMain* uiMain; }; struct GameData { /*0x0000*/ char unk_0000[0x48]; /*0x0048*/ uint16_t playerCount; /*0x004A*/ uint16_t unk_004A; /*0x004C*/ Player** players; /*0x0050*/ char unk_0050[0x48]; /*0x0098*/ uint16_t activePlayerIndex; /*0x009A*/ uint16_t unk_009A; /*0x009C*/ float cameraPosX; /*0x00A0*/ float cameraPosY; /*0x00A4*/ char unk_00A4[0xC]; /*0x00B0*/ Unit** objectArray; /*0x00B4*/ uint32_t objectCount; /*0x00B8*/ uint32_t objectMax; }; struct UIMain { /*0x000000*/ char unk_0000[0x13B14]; /*0x013B14*/ void* unk_013B13; /*0x013B18*/ UITextElement* chatRows[8]; /*0x013B38*/ void* unk_013B38; /*0x013B3C*/ uint32_t chatRowsCount; /*0x013B40*/ char unk_013B40[0x8]; /*0x013B48*/ UITextElement* pauseText; // actually different kind of ui element }; struct UITextElement { /*0x0000*/ void* vtbl; /*0x0000*/ char unk_0004[0x10]; /*0x0014*/ uint32_t xLength; /*0x0018*/ uint32_t yLength; /*0x001C*/ char* elementName; /*0x0020*/ char unk_0020[0xEC]; /*0x010C*/ char text[0x200]; /*0x030C*/ BOOL isShown; /*0x0310*/ uint32_t timeSent; /*0x0314*/ uint32_t timeToShow; /*0x0318*/ void* unkArg1; /*0x031C*/ void* unkArg2; /*0x0320*/ void* unkArg3; /*0x0324*/ char color; /*0x0325*/ char unk_0325[0x3]; /*0x0326*/ char unk_0326[0x1C]; /*0x0342*/ DrawingData* drawingData; }; struct DrawingData { /*0x0000*/ char unk_0000[0x20]; /*0x0020*/ HDC dcHandle; }; struct Player { /*0x0000*/ void* vtbl; /*0x0004*/ char unk_0004[0x6C]; /*0x0070*/ uint32_t priceCount; /*0x0074*/ Price** priceTable; /*0x0078*/ ObjectManager* objectManager; /*0x007C*/ char unk_007C[0x1C]; /*0x0098*/ char* name; /*0x009C*/ char unk_009C[0xC]; /*0x00A8*/ Resources* resources; /*0x00AC*/ char unk_00AC[0xC8]; /*0x0174*/ float cameraPosX; /*0x0178*/ float cameraPosY; /*0x017C*/ char unk_017C[0x44]; /*0x01C0*/ Unit* lastSelectedUnit; /*0x01C4*/ Unit* selectedUnits[60]; /*0x02B4*/ void* unk_02B4; /*0x02B8*/ uint32_t selectedUnitsCount; }; struct Unit { /*0x0000*/ void* vtbl; /*0x0004*/ uint32_t unitID; /*0x0008*/ UnitData* unitData; /*0x000C*/ Player* owner; /*0x0010*/ char* name1; /*0x0014*/ char* name2; /*0x0018*/ char unk_0018[0x18]; /*0x0030*/ float hp; /*0x0034*/ uint16_t unk_0034; /*0x0036*/ uint16_t isSelected; /*0x0038*/ float posXReadOnly; /*0x003C*/ float posY1ReadOnly; /*0x0040*/ void* unk_0040; /*0x0044*/ float resourcesCarryingCount; /*0x0048*/ char unk_0048[0x3C]; /*0x0084*/ float velocity; /*0x0088*/ char unk_0088[0x3C]; /*0x00C4*/ float posX; /*0x00C8*/ void* unk7; /*0x00CC*/ float posY; /*0x00D0*/ float rotation; /*0x00D4*/ char unk_00D4[0x38]; /*0x010C*/ TargetPtr* targetDataPtr; }; struct UnitData { /*0x0000*/ char unk_0000[0xCC]; /*0x00CC*/ float speed; }; struct TargetPtr { /*0x0000*/ char unk_0000[0x8]; /*0x0008*/ TargetData** targetData; }; struct TargetData { /*0x0000*/ char unk_0000[0x8]; /*0x0008*/ Unit* thisUnit; /*0x000C*/ void* unk_000C; /*0x0010*/ Unit* targetUnit; // 0 no target /*0x0014*/ void* unk_0014; /*0x0018*/ uint32_t targetID; /*0x001C*/ void* unk_001C; /*0x0020*/ float destinationX; // -1 no destination /*0x0024*/ float destinationY; // -1 no destination /*0x0028*/ float isMoving; // -1 not moving 0 moving }; struct ObjectManager { /*0x0000*/ void* unk_0000; /*0x0004*/ Unit** objects; /*0x0008*/ uint32_t objectCount; }; struct Price { /*0x0000*/ void* vtbl; /*0x0004*/ char* name; /*0x0008*/ char unk_0008[0x10]; /*0x0018*/ short typeID; /*0x001A*/ char unk_001A[0x15A]; /*0x0174*/ uint16_t resourceType1; /*0x0176*/ uint16_t cost1; /*0x0178*/ uint16_t priceUnk1; /*0x017A*/ uint16_t resourceType2; /*0x017C*/ uint16_t cost2; /*0x017E*/ uint16_t priceUnk2; /*0x0180*/ uint16_t ResourceType3; /*0x0182*/ uint16_t cost3; /*0x0184*/ uint16_t priceUnk3; /*0x0186*/ uint16_t buildTime; }; struct Resources { /*0x0000*/ float food; /*0x0004*/ float wood; /*0x0008*/ float stone; /*0x000C*/ float gold; /*0x0010*/ float populationLeft; /*0x0014*/ void* unk_0014; /*0x0018*/ float age; /*0x001C*/ char unk_001C[0x10]; /*0x002C*/ float population; /*0x0030*/ char unk_0030[0x1C]; /*0x004C*/ float unitsProduced; /*0x0050*/ char unk_0050[0x8]; /*0x0058*/ float percentageExplored; }; struct BuildEventArgs { /*0x0000*/ char unk_0000; /*0x0001*/ char builderCount; /*0x0002*/ char playerID; /*0x0003*/ char unk_0003; /*0x0004*/ float posX; /*0x0008*/ float posY; /*0x000C*/ uint16_t buildingID; /*0x000E*/ uint16_t unk_000E; /*0x0010*/ char unk_0010[0x8]; /*0x0018*/ uint32_t builderID[0]; }; struct ChatLog { /*0x0000*/ char unk_0000[0x58]; /*0x0058*/ char* msg[0]; };Code:// this = unit(victim) float(__stdcall* GetDamage)(uint32_t attackType, float unkFloat_1, float unkFloat_2, Player* attackerPlayer, Unit* attackerUnit) = 0x0061B360; // this = unit float(__stdcall* MoveUnit)(float posX, float posY, uint32_t unk0) = 0x004B3900; // this = unit void(__stdcall* ChangeOwner)(Player* newOwner) = 0x004AB0F0; // this = building(unit) void(__stdcall* TrainUnit)(uint32_t unitID, uint32_t unk1) = 0x005409E0; // this = unit void(__stdcall* SetTargetUnit)(Unit* targetUnit, float posX, float posY, uint32_t unk0, uint32_t unk0_2, uint32_t unkMinus1) = 0x0061B510; // this = unit void(__stdcall* SetTargetLocation)(uint32_t unk0_1, float posX, float posY, uint32_t unk0_2) = 0x00621830; // this = price Unit*(__stdcall* CreateBuilding) (Player* player, float posX, float posY, uint32_t unk0, uint32_t unkMinus1) = 0x0044E120; // this = struct { uint32_t unk; GameData* ptr; } void(__stdcall* BuildStructure) (BuildEventArgs* args) = 0x004E18A0; // this = player void(__stdcall* DeselectAllUnits)(void) = 0x005D2FB0; // this = player void(__stdcall* SelectUnit)(Unit* unit, uint32_t unk0) = 0x0047A990; // this = UITextElement void(__stdcall* PrintText)(uint32_t position, char* msg, char color, uint32_t unk0_1, uint32_t unk0_2, uint32_t unk0_3, uint32_t unk0_4, uint32_t timeToShow, uint32_t unk0_5, uint32_t unkMinusOne) = 0x445D90; // this = UITextElement void(__stdcall* DrawUIText)() = 0x5C82F0;
Example scripts:
Kill all units in game apart from yours and the GAIA ones (seems to work even in multiplayer, but would need some 3rd party to confirm.
"Teleport Hack" for your units (wanted to hook the movement event, but its protected from hooking by the steam):Code:void AnalRape() { uint16_t playerCount = mainClassPointer->gameMain->playerCount; for (int i = 2; i < playerCount; i++) { Player* player = mainClassPointer->gameMain->players[i]; ObjectManager* mgr = player->objectManager; int objCount = mgr->objectCount; for (int i2 = 0; i2 < objCount; i2++) { Unit* unit = mgr->objects[i2]; unit->hp = 0.0; } } }
Code:float __stdcall MoveUnitHook(float posX, float posY, uint32_t unk0) { Unit* unit; __asm mov unit, ecx if (mainClassPointer->gameMain->players[1] == unit->owner) { if ((uint32_t)unit->targetDataPtr > 0x400000) { TargetData** target = unit->targetDataPtr->targetData; float destX = (*target)->destinationX; float destY = (*target)->destinationY; if (destX > 0 && destY > 0) { posX = destX; posY = destY; } } } __asm mov ecx, unit MoveUnitTrampoline(posX, posY, unk0); }






Reply With Quote

