Is this information gathered automatically via a script?
I can painstakingly find offsets and memory locations, but how do people dump them so easily like this?
Very nice, again thank you!
Functions don'change.
Search FindPattern.
Basics:
Patterns are made with a decompiler (like IDA).Code:#define START 0x00401000 #define END 0x00A00000 class Pattern { protected: const char* m_pattern; const char* m_mask; public: Pattern(const char* _pattern, const char* _mask) : m_pattern(_pattern), m_mask(_mask) {} bool Found(unsigned int _addr) const { for (unsigned int i = 0; m_mask[i]; i++) { if (m_mask[i] == 'x' && *(char*)(_addr+i) != m_pattern[i]) return false; } return true; } }; void* FindDostring() { for (unsigned int i = START; i < END; i++) if (Pattern("\x55\x8B\xEC\x51\x83\x05\xCC\x74\x32\x01\x01\xA1\xC8\x74\x32\x01\x89\x45\xFC\x74\x12\x83\x3D\xD0\x74\x32\x01\x00", "xxxxxx????xx????xxxxxxx????x").Found(i)) return (void*)i; return 0; };
Last edited by eLaps; 04-20-2010 at 02:53 PM.
A. Patterns
Already explained above. Create search patterns and apply them to the executable file. It's a bit of a PITA to create patterns that work across versions and still yield unique matches. I think Cypher's HadesMem C++ library has a PE pattern matching implementation.
B. IDA Pro
If you use IDA Pro, here's one way to do it:
0) You have named a few functions in the current binary and now a patch arrives.
1) Use Tenable Security's PatchDiff2 to match functions between the known binary and the update. PatchDiff2 will give you list of identical, matched & unmatched functions.
2) Copy & paste the output of PatchDiff2 into a text file.
Get a program that converts this file into a new text file with the line format "${OFFSET} ${FUNCTION_NAME}", e.g. "1234BEEF ClickToMove".
There's a C# Windows program for that. (edit) Forgot its name. I'm using a quick & dirty Python script instead:
3) Get an IDC script that imports the text file from step 2 to rename the functions in the new binary. So far I've used this .IDC script but found a second script, yet untested, too.Code:#!/usr/bin/python2.6 """ This script converts PatchDiff2 output to a simple "Offset Name" format. Author: sednogmah (mmowned.com) """ import sys import re ### main re_identical = re.compile(r'^(?P<engine>\d+)\s+(?P<funcname1>.*?)\s+(?P<funcname2>.*?)\s+(?P<addr1>\w+)\s+(?P<addr2>\w+)\s+(?P<crc>[+-])\s+(?P<crc1>\w+)\s+(?P<crc2>\w+)\s*') if len(sys.argv) != 2: print >>sys.stderr, "Usage: pd2-sanitizer.py patchdiff2-output.txt" sys.exit(1) filename = sys.argv[1] for line in open(filename, "r"): if re_identical.match(line): result = re_identical.search(line).groupdict() if re.match(r'.*[()].*', result["funcname2"]): continue if re.match(r'^(sub_|SEH_).*', result["funcname1"]): continue print "%08X \t %s" % (int(result["addr2"], 16), result["funcname1"])
Last edited by Sednogmah; 04-20-2010 at 07:45 PM.
951388dcb8e5be825c2c10a7f53c16fcd84fc6c8b76ff0483237eeff745eaeac
Camera base is unchanged
[0x00BF2AF8] + 0x7E24
Last edited by Jadd; 04-22-2010 at 06:13 AM.
0xC4EB68 FocusGUID
Didn't tested but should be ok.
Exactly, the name cache is a set of linked-lists where the player guid determines which of the linked lists the name is stored in, noddy example of how to use the name cache (C#)
Code:public static string GetPlayerNameByGuid( ulong guid ) { const uint nameStorePtr = 0xBB92A0 + 0x8; // Player name cache const uint nameMaskOffset = 0x24; const uint nameBaseOffset = 0x1C; const uint nameStringOffset = 0x20; uint base_addr, offset, current, testGUID; uint mask = Memory.Read<UInt32>((IntPtr)(nameStorePtr + nameMaskOffset)); base_addr = Memory.Read<UInt32>((IntPtr)(nameStorePtr + nameBaseOffset)); uint shortGUID = (uint)guid & 0xffffffff; uint x = (mask & shortGUID); offset = 12 * x; current = Memory.Read<UInt32>((IntPtr)(base_addr + offset + 8)); offset = Memory.Read<UInt32>((IntPtr)(base_addr + offset)); if ((current == 0) || (current & 0x1) == 0x1) return "Unknown"; testGUID = Memory.Read<UInt32>((IntPtr)(current)); string testName = Memory.ReadString((IntPtr)(current + nameStringOffset), 40); while (testGUID != shortGUID) { current = Memory.Read<UInt32>((IntPtr)(current + offset + 4)); if ((current == 0) || (current & 0x1) == 0x1) return "Unknown"; testGUID = Memory.Read<UInt32>((IntPtr)current); } // Found the guid in the name list... string str = Memory.ReadString((IntPtr)(current + nameStringOffset), 40); return str; }
The simpler option is to just read the damned CCreatureInfo struct out of the unit's class fields. (Or struct fields as it would be.)
Added some labels to show the offsets to read from.Code:[StructLayout(LayoutKind.Sequential)] internal unsafe struct NativeWoWUnit { public NativeWoWObject Object; // 0xCC public UnitDescriptors* UnitInfo; // 0xD0 public uint Unk; // 0xD4 public MovementData* MovementInfoPtr; // 0xD8 private fixed byte UnitPadding0 [1708]; // 0xDC private MovementData MovementInfo; // THis is the static version of the one at 0xD8 private fixed byte UnitPadding1 [148]; public CCreatureInfo* CreatureInfo; // 0x940 private fixed byte UnitPadding2 [1696]; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] internal unsafe struct CCreatureInfo { private byte Unk [4]; public char* SubName; public char* IconName; public int TypeFlags; public int TypeID; public int FamilyID; public int Rank; public int GroupID; public int GroupID2; public int SpellDataID; public int ModelID1; public int ModelID2; public int ModelID3; public float HealthMod; public float ManaMod; public byte RacialLeader; private fixed byte gap_3d [3]; public fixed int QuestItem [6]; public int MovementId; public fixed uint Names [4]; }
Keep in mind; CCreatureInfo->NameStore[4] is the actual unit name. (And the one retrieved from CGUnit_C__GetUnitName)
Last edited by Apoc; 05-02-2010 at 11:17 AM.
Edit: Solved
Code:protected const uint AURA_COUNT_1 = 0xdd0; protected const uint AURA_COUNT_2 = 0xc54; protected const uint AURA_SIZE = 0x18; protected const uint AURA_SPELL_ID = 8; protected const uint AURA_TABLE_1 = 0xc50; protected const uint AURA_TABLE_2 = 0xc58;
Last edited by fukmeimbroken; 05-10-2010 at 03:54 AM.
Some ClientServices funcs (some might be posted already):
The struct I reversed with:Code:00406F20 ClientServices__SendPacket 004644B0 ClientServices__ClientServices 004646E0 ClientServices__Destroy 0061F2B0 ClientServices__Create 0061F320 ClientServices__StatusCodeToString 0061F980 ClientServices__IsPlayerLoggingOut 0061F990 ClientServices__Disconnect 0061F9D0 ClientServices__GetCurrent 0061FB40 ClientServices__SendToCurrent 0061FB60 ClientServices__SetHandler 0061FB80 ClientServices__ResetHandler 0061FEC0 ClientServices__GetErrorToken 0061FEE0 ClientServices__IsCurrent 00620000 ClientServices__LoginFailure 00620050 ClientServices__PollStatus 00620140 ClientServices__SetStatusCode 006202D0 ClientServices__Connect 006203E0 ClientServices__GetCharacters 00620530 ClientServices__CreateCharacter 00620750 ClientServices__LoginSuccess 00620960 ClientServices__DeleteCharacter 00621160 ClientServices__Initialize 006B8190 ClientServices__GetSessionKey 006B9AA0 ClientServices__CanSendOpcode 008EFBB0 ClientServices__SendData
(Yes, I'm aware the beginning of the struct is outright wrong; I didn't bother reversing the NetClient part.)Code:#pragma pack(push, 1) struct ClientServices { void *vTable1; void *m_Handlers[2991]; void *vTable2; _BYTE f2EC4[40]; _DWORD dword2EEC; _DWORD dword2EF0; _DWORD dword2EF4; _BYTE byte2EF8; _BYTE f2EF9[3]; _DWORD dword2EFC; _DWORD dword2F00; _DWORD m_BillingTimeRemaining; _DWORD m_BillingTimeRested; _BYTE m_BillingFlags; _BYTE m_ExpansionLevel; _BYTE f2F0E[2]; _DWORD m_IsConnectedToServer; _DWORD dword2F14; _DWORD m_IsInQueue; _DWORD dword2F1C; _DWORD m_ConnectionStatus; _DWORD m_RealmStatus; _DWORD m_IsConnected; _BYTE m_IsLoggedIn; _BYTE m_PlayerLoggingOut; _BYTE byte2F2E; _DWORD dword2F32; }; #pragma pack(pop)
---------- Post added at 07:27 PM ---------- Previous post was at 07:23 PM ----------
00561C20 SHA1__Initialize
0060EC00 SHA1__Update
0060ECF0 SHA1__Finalize
Last edited by XTZGZoReX; 05-11-2010 at 12:26 PM.