-
Legendary
[C#] Enigma.D3 (2.x)
IF YOU HAVE A QUESTION RELATED TO THIS THEN WRITE IN THE THREAD INSTEAD OF SENDING ME A PM! KTHXBYE
This is a 2.x update to (read that thread for more info):
[C#] 1.0.8.16603 Enigma.D3
Been reversing D3
with IDA for a while now and thought it was time for sharing. I do this primarily to learn and as a challenge so I don't really have any useful programs based on this framework. Don't be surprised if something is not quite working out or not making sense.
Please spare me the PMs asking to do this and that for payment, I'm not interested!
Credits:
KillerJohn for beeing a great sparring partner and for providing puzzles to solve.
DarthTon for the public framework which helped when getting started with all of this.
boredevil for a few posts that got me interested in assembly and IDA.
D3\Engine.cs contains the static offsets and is probably a good place to start exploring.
Properties using Read<T> are fields inside the structure. Any 2nd argument specifies an array length.
Properties using Dereference<T> however are pointers. Any 2nd argument specifies an array length.
Names starting with _ means I've seen no usage in IDA (doesn't mean it's not used).
Names ending with _ means I'm not sure if the name I've given is an accurate representation.
Note that D3 has the /LARGEADDRESSAWARE option, meaning it can access up to 3GB memory!
See Enigma.D3.ApplicationModel for a high level API.
See Enigma.D3.MemoryModel for a low level API.
See Enigma.D3.MapHack for a demo application.
Find latest source at: GitHub - Enigma32/Enigma.D3
Last edited by enigma32; 07-22-2017 at 11:35 AM.
-
Post Thanks / Like - 14 Thanks
Inject,
gunboxer,
prrovoss,
sh00ter999,
johnbl,
DarkLinux,
Torpedoes,
Parog,
perp|ex,
Comment,
AL3x3y0,
ZenDraL,
d2k2,
731113 (14 members gave Thanks to enigma32 for this useful post)
-
Private
-
Private
-
Private
Wow! Great work enigma.
Once I removed heroselect.cs from the project it compiled.
I have a question regarding getting my actors current experience and next level experience for paragon. Alt_Experience_Next Lo and High are incorrect.
Just wondering if anyone can check and confirm that this is the case or if it is just me.
Once again, fantastic work!
-
Contributor
Originally Posted by
Logikaljay
Wow! Great work enigma.
Once I removed heroselect.cs from the project it compiled.
I have a question regarding getting my actors current experience and next level experience for paragon. Alt_Experience_Next Lo and High are incorrect.
Just wondering if anyone can check and confirm that this is the case or if it is just me.
Once again, fantastic work!
You are reading the attribute from the player actor right?
Enigma great job as always +Rep
-
Legendary
Originally Posted by
Logikaljay
Once I removed heroselect.cs from the project it compiled.
Thanks, I re-uploaded the archive with a corrected project file At the same time I finally figured out how to rename thread. Couldn't find that last time hence why I created a new thread, didn't want the old D3 version number in the title
Originally Posted by
Logikaljay
I have a question regarding getting my actors current experience and next level experience for paragon. Alt_Experience_Next Lo and High are incorrect.
Just wondering if anyone can check and confirm that this is the case or if it is just me.
They appear to be working for me. However, if you're using my helper then beware that the return type is double which might not work so great if combining 2 values into a long.
My remaining exp calculated from game UI: 118560658
ActorCommonDataHelper.GetLocalAcd().GetAttributeValue(AttributeId.Alt_Experience _Next_Lo); => 118560656 (inaccurate)
ActorCommonDataHelper.GetLocalAcd().GetAttributeValue(AttributeId.Alt_Experience _Next_Hi); => 0
Not sure why casting to double looses precision here, should be able to handle it afaik... The attribute value is actually same as UI calculation when I read it as int.
Last edited by enigma32; 04-04-2014 at 06:56 PM.
-
Private
Amazing, thanks! Just curious, how do you update the offsets in Engine.cs every time the game is patched?
-
Legendary
Originally Posted by
tanvandan
Amazing, thanks! Just curious, how do you update the offsets in Engine.cs every time the game is patched?
1. Load new binary in IDA (takes about an hour on my computer)
2. Create pattern file for previous exe using the plugin "IDA2PAT Reloaded".
3. Convert the pattern file into a signature file. Multiple methods could end up with the same pattern, so have to manually filter what should be kept or not so there is no conflict.
4. Once IDA is done analyzing new patch, make it scan for the signatures that were created from previous exe.
5. Export all structs to a header file and import in new IDA database. Sadly all type information is lost, I only get names of methods, return types and arguments will all be int, void* and crap like that
6. Once that is done, I have to go to the various methods (hopefully I remember their names) and see what has changed. Static offsets are kinda easy, but sizes and fields of things are more bothersome, and the further down the pointer chain the more pain in the ass it is often.
I've written some experimental code that is able to search using data from the pattern file, so in theory I could have all static offsets within a few seconds after new exe being patched. But validating fields, logic, sizes, structure... here I have no easy way. Best thing would be to have a program that depends on them and see what breaks, but I don't really have any and that's why I'm asking for interfaces and demo projects
-
Private
Ah I see it is the experience remaining! Silly me.
Fantastic work enigma! Can't believe the amount of hours this must have taken!
Mad skills
This might be a silly question. But is there a way to get the current Experience and Experience needed?
I can't seem to find these values in the attributes. Or do I have to build a list of the experience needed per level and work it out from experience remaining and level data from attributes.
Last edited by Logikaljay; 04-04-2014 at 08:08 PM.
-
Member
oh you're my hero, this is just the thing i need to fix my script.
-
Member
ok, i check the FastAttribGroup structure a bit, but there seem to be issues.
This is one dump of FastAttribGroup:
Code:
0000 - B6 00 8A 78 09 00 00 00 FF FF FF FF 00 00 00 00
0010 - FF 00 00 00 10 00 00 00 80 D9 1C 2A 00 00 00 00
0020 - DC F4 FC 23 00 00 00 00 00 01 00 00 00 00 00 00
0030 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
The id is ok, but later fields seems to be the wrong. At first glance, 0x2A1CD980 and 0x23FCF4DC looks like pointer, so i dump them:
Code:
0000 - 0C 00 00 00 00 24 00 00 03 00 00 00 00 E0 36 49
0010 - 00 02 02 00 00 00 00 00 0D F0 0D 60 0C 00 00 00
0020 - 80 01 00 00 02 00 00 00 00 B4 D4 56 00 02 02 00
0030 - 00 00 00 00 0D F0 0D 60 0C 00 00 00 00 04 00 00
0040 - 01 00 00 00 00 08 20 37 00 02 02 00 00 00 00 00
0050 - 0D F0 0D 60 80 41 FF 14 00 00 00 00 00 00 00 00
0060 - 24 8E FD 1F D0 46 A9 01 E4 46 A9 01 00 00 00 00
0070 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
This is supposed to be the hash map, but again i'm at a lost.
-
Legendary
Originally Posted by
virgil123
ok, i check the FastAttribGroup structure a bit, but there seem to be issues.
This is one dump of FastAttribGroup:
Code:
0000 - B6 00 8A 78 09 00 00 00 FF FF FF FF 00 00 00 00
0010 - FF 00 00 00 10 00 00 00 80 D9 1C 2A 00 00 00 00
0020 - DC F4 FC 23 00 00 00 00 00 01 00 00 00 00 00 00
0030 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
The id is ok, but later fields seems to be the wrong. At first glance, 0x2A1CD980 and 0x23FCF4DC looks like pointer, so i dump them:
Code:
0000 - 0C 00 00 00 00 24 00 00 03 00 00 00 00 E0 36 49
0010 - 00 02 02 00 00 00 00 00 0D F0 0D 60 0C 00 00 00
0020 - 80 01 00 00 02 00 00 00 00 B4 D4 56 00 02 02 00
0030 - 00 00 00 00 0D F0 0D 60 0C 00 00 00 00 04 00 00
0040 - 01 00 00 00 00 08 20 37 00 02 02 00 00 00 00 00
0050 - 0D F0 0D 60 80 41 FF 14 00 00 00 00 00 00 00 00
0060 - 24 8E FD 1F D0 46 A9 01 E4 46 A9 01 00 00 00 00
0070 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
This is supposed to be the hash map, but again i'm at a lost.
public Map<int, Pointer> x00C_PtrMap { get { return Dereference<Map<int, Pointer>>(0x00C); } } // <-- this one is 0 for you, so it can be skipped for this group
public Map<int, Pointer> x010_Map { get { return Field<Map<int, Pointer>>(0x010); } } <-- this is not a pointer to the hash table! very important!
0x2A1CD980 would be the pointer to an allocator, probably the bucket allocator.
0x23FCF4DC would be the pointer to the hash table buckets (x010_Map.x10_Data.x00_BucketPointers = offset 0x20 as no pointer is used for this)
Your dump of what is supposed to be hash table is wrong, that is an allocator. I can tell from the 0x600DF00D (goodfood) at 0x18, BasicAllocator.x18_GoodFood.
-
Legendary
Originally Posted by
Logikaljay
Fantastic work enigma! Can't believe the amount of hours this must have taken!
Mad skills
This might be a silly question. But is there a way to get the current Experience and Experience needed?
I can't seem to find these values in the attributes. Or do I have to build a list of the experience needed per level and work it out from experience remaining and level data from attributes.
Thanks Has taken countless hours indeed, but oh so much I've learned from it. When I first started with IDA I had absolutely no idea about anything... I had never done anything advanced in low level C languages, only had plenty of experience with C#. Now I'm fairly knowledgeable about memory structures, pointers, virtual tables, class inheritance, exception handling, PE structure, x86 architecture and so on
OK back to your question! As far as I know, you would need the experience table in order to determine how far into a level one are. I don't know where to access it in memory (yet) so you would need a dump from the MPQ files or find it on the internet.
-
Member
Originally Posted by
enigma32
public Map<int, Pointer> x00C_PtrMap { get { return Dereference<Map<int, Pointer>>(0x00C); } } // <-- this one is 0 for you, so it can be skipped for this group
public Map<int, Pointer> x010_Map { get { return Field<Map<int, Pointer>>(0x010); } } <-- this is not a pointer to the hash table! very important!
0x2A1CD980 would be the pointer to an allocator, probably the bucket allocator.
0x23FCF4DC would be the pointer to the hash table buckets (x010_Map.x10_Data.x00_BucketPointers = offset 0x20 as no pointer is used for this)
Your dump of what is supposed to be hash table is wrong, that is an allocator. I can tell from the 0x600DF00D (goodfood) at 0x18, BasicAllocator.x18_GoodFood.
Oh, how foolish of me ! Yeah, it works nicely now, thanks again for the great work,
-
Private
Has anyone experienced Engine.Current.ObjectManager becomming null randomly?
My situation:
I have a timer firing every 75 milliseconds, calculating the difference in 'Current Experience' to the old value of 'Current Experience'.
It also gathers some character information, level, class, str, dex, int, vit, armor, health, etc etc.
It will work fine for awhile, but after roughly 1-2 mins ObjectManager becomes null and it stops working.
Weird bug I know, but kind of annoying!
Any insight from people more skilled in this that me would be greatly appreciated.