Sign in to follow this  
Followers 0
Nomad

Defeating DMA without...

14 posts in this topic

#1 ·  Posted (edited)

This is a little script I wrote that gets the stats of a character in a game of Diablo II. This script is a "stand alone" script that does not inject any .dll or run any code caves to defeat the Dynamic Memory Allocation of the game. I have seen other articles and posts on this, but until now I have not seen a post that provided the theory along with a "working" example (at least not for this game). This script uses Kernel32.dll's ReadProcessMemory function to access this information.

This script's structure was based on a program written in C by Netter. This script was also based on wOuter's _Mem() functions. However, w'Outer's _Mem() functions would not read some of the addresses required to defeat the DMA for the game. I am not entirely sure why, but I have modeled my memory reading function based on his original functions. His functions would read some of the addresses flawlessly, but would return a 0 value on others. Maybe this script will aid him in debugging his functions as well. Thanks go out to him none the less.

If you use this script in whole, or in structure, please credit the proper individuals accordingly.

;======================================================================
; AutoIt Version: 3.0 beta
; Language:       English
; Platform:       Win9x/NT or newer
; Author:         Nomad
; Requirements:
;       None.  This script "should" run on any version of windows.
;       This script will only work with beta.  Contact me via pm
;       if you don't have beta and would like a .exe to try this out.
;======================================================================
; Script Function:
;   Checks the stats of a player in a game of Diablo II.
;   This script is a "proof of concept" that it is possible to defeat
;   Dynamic Memory Allocation in AutoIt without modifying any of the
;   installed programs.
;======================================================================
; Credits:
;
;   Netter:
;   This script is based on a program written by Netter.  Netter's
;   program was written in C.  So Netter deserves some of the credit
;   for this script since it is based on his original program.
;
;   wOuter:
;   wOuter also deserves some credit since the DllCalls are based on
;   his _Mem () function UDF's.
;======================================================================
; Additional:
;   If you use this script, or modify this script for use, in any of
;   your scripts, please credit me and all contributors accordingly.
;======================================================================

#cs
If you are unable to get your stats, then you may need administrative
rights to be enabled with SeDebugPrivilege.  I am not sure if you need
them or not for this script.
#ce

#cs
A few sample numbers to enter for stats:
(naked) = base... before adding bonuses from items, charms, skills, w/e
(So it's possible for the current to show higher than the max if you're current is at max with items or w/e)
-27 = (naked) strength
-19 = (naked) energy
-11 = (naked) dexterity
-3 = (naked) vitality
6 = current life
14 = max (naked) life
22 = current mana
30 = max (naked) mana
38 = current stamina - found by Busti
46 = max (naked) stamina - found by Busti
53 = current level
61 = current experience

There might be others, these are just some.
I could change the program so they would all be positive, but not really the point right now.
#ce

Global $GlobalPlayerUnit = 0x6FBCC1E0, $pid

While (1)
Main ()
WEnd

Func Main ()
    If InitD2 () = 0 Then Exit
    $InputBoxAnswer = InputBox("Which Stat To Check","Input the number which corresponds to the stat you would like to check:",""," ", 210, 130, -1, -1)
    Select
        Case @Error = 0
            If $InputBoxAnswer >= -40 and $InputBoxAnswer <= 133 Then
                $StatValue = GetStat ($InputBoxAnswer)
                MsgBox(0, "Value of Stat", "The value of stat #" & $InputBoxAnswer & " is: " & $StatValue)
                Return
            Else
                MsgBox(0, "ERROR", "Input a number between -40 and 133")
                Return
            EndIf
        Case @Error = 1
            Exit
        Case @Error = 3
            MsgBox(0, "ERROR", "The Input Box failed to open")
            Exit
    EndSelect
EndFunc

Func InitD2 ()
    If ProcessExists('D2Loader.exe') Then
        $pid = ProcessExists('D2Loader.exe')
        Return 1
    ElseIf ProcessExists('Diablo II.exe') Then
        $pid = ProcessExists('Diablo II.exe')
        Return 1
    Else
        MsgBox(0, "ERROR", "No instances of Diablo II are running.")
        Return 0
    EndIf
EndFunc

Func GetStat ($InputBoxAnswer)
    Local $Buffer = DllStructCreate('dword')
    Local $dll[2] = [DllOpen('kernel32.dll')]
    Local $Open = DllCall($Dll[0], 'int', 'OpenProcess', 'int', 0x1F0FFF, 'int', 0, 'int', $pid)
    $dll[1] = $Open[0]
    DllCall($dll[0], 'int', 'ReadProcessMemory', 'int', $dll[1], 'int', $GlobalPlayerUnit, 'ptr', DllStructGetPtr($Buffer), 'int', 4, 'int', '')
    $Pointer1 = '0x' & hex(DllStructGetData($Buffer, 1) + 92)
    DllCall($dll[0], 'int', 'ReadProcessMemory', 'int', $dll[1], 'int', $Pointer1, 'ptr', DllStructGetPtr($Buffer), 'int', 4, 'int', '')
    $Pointer2 = '0x' & hex(DllStructGetData($Buffer, 1) + 36)
    DllCall($dll[0], 'int', 'ReadProcessMemory', 'int', $dll[1], 'int', $Pointer2, 'ptr', DllStructGetPtr($Buffer), 'int', 4, 'int', '')
    $Pointer3 = '0x' & hex(DllStructGetData($Buffer, 1) + $InputBoxAnswer + 31)
    DllCall($dll[0], 'int', 'ReadProcessMemory', 'int', $dll[1], 'int', $Pointer3, 'ptr', DllStructGetPtr($Buffer), 'int', 4, 'int', '')
    $Value = DllStructGetData($Buffer, 1)
    DllClose($dll[0])
    Return $Value
EndFunc

Enjoy,

Nomad :P

Edit: left out a line of code by mistake. :D

Edit: Added some more stats

Edit: Added some more stats, I still haven't located the max stats after bonuses though. They are probably stored on a different area of the memory since it would have to cross reference the items, charms, w/e before applying.

Edit: I quit monitoring this script a few weeks ago. I just thought I would add that this script is not 100% accurate on anything except the strength, dexterity, energy, and vitality. The reason is because the main address is a pointer to your Player Unit. Your Player Unit consists of many things, including all gear you currently have equipped. Different gear gives different stats and adds more information to your Player Unit. All of this gear and stuff is located in addresses that are meshed with the addresses for other things, such as life. So if the amount of space required to hold your gear stats increases, it moves the memory addresses of the other stats. I've noticed that they move by 64 bytes at a time (so instead of entering 6 for current life, you might need to enter 14, or 22, or 30, etc..). I just thought I would point this out. This is just a "proof of concept", not a "ready for production" script. :D

Note: Also, if you are trying to read your current experience, if it is over 2,147,483,647, at 2,147,483,648 it will become -2,147,483,647 and count up from there since AutoIt uses 32 bit signed integers by default. You can defeat this by converting the value to a string and doing some string manipulation though.

Edited by Nomad

Share this post


Link to post
Share on other sites



realyrealyrealy nice !!! works 100% !!!


My UDF's : Startet on : 06.06.2006_CaseSearchOrReplaceStr();~> Searches OR Replaces a String,;~> With or Without Casesensivity

Share this post


Link to post
Share on other sites

This is nice, I really like it. Good job.


Ha, I haven't been on these forums since... 2006, almost. Behold, my legacy signature:My AutoIt idol is Valuater. You know you love him, too.My Stuff: D&D AGoT Tools Suite

Share this post


Link to post
Share on other sites

i found something out :

38 = CurrentStamina

46 = MaxStamina

=)


My UDF's : Startet on : 06.06.2006_CaseSearchOrReplaceStr();~> Searches OR Replaces a String,;~> With or Without Casesensivity

Share this post


Link to post
Share on other sites

Thanks for the complements. It took a lot of debugging work to figure out the pointers, then a little more work to get kernel32.dll to read the memory properly. But I'm happy with the results. :D

i found something out :

38 = CurrentStamina

46 = MaxStamina

=)

Cool, I'll have to check that out later. That could be a useful thing to know for bots. I didn't spend a lot of time trying to figure out what addresses held what. I was more concerned with just getting a reading on the current life when I started this project. :D

Special thanks to Netter for some light tutoring on debugging as well as providing the program in C upon which this program was based.

Also to wOuter for his original _Mem() functions. They provided the foundation from which I based the DllCalls.


Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

how did you get that with dllsetstruct etc. ?

and that with

+16...

+32...

etc.^^

how did you find that out ?!ß1ß1

and can you find the coordinates of the player ? and more ? or only the 111 things working ?

and would something like this or this work in WoW too ?

Edited by Busti

My UDF's : Startet on : 06.06.2006_CaseSearchOrReplaceStr();~> Searches OR Replaces a String,;~> With or Without Casesensivity

Share this post


Link to post
Share on other sites

how did you get that with dllsetstruct etc. ?

and that with

+16...

+32...

etc.^^

how did you find that out ?!ß1ß1

and can you find the coordinates of the player ? and more ? or only the 111 things working ?

and would something like this or this work in WoW too ?

This concept should work with any program, but this script itself will only work with Diablo II.

You read the stats, or any value you want, directly from the memory address which is holding the value you want. But with DMA (Dynamic Memory Allocation), these addresses are different each time you start the game, or program. They also change under other circumstances, such as leaving a game joining another. Programs do this to save memory space. That way the program does not have to allocate a memory address for values which are not needed at the specific point in the program. If the program allocated every single memory address it could possibly use when you started the program, it would probably eat up 3 to 4 times the available memory (depending on the program, some less, some more).

But, in order for DMA to work the program itself must know where these addresses are located. The program uses "Pointers" to locate these addresses. Pointers can also be assigned using DMA, which is the case in Diablo II, but somewhere there must be a "Static Pointer" or DMA will not work because the program will not know where to look. A Static Pointer is a fixed address that is not dynamically allocated. That means that no matter what you do, the address will never change (when a game is patched this address could change though, like when D2 releases the 1.12 patch).

The +16, +32, etc.. is the Offset which must be added to the value of the Pointer you are currently reading to get the address of the next Pointer in the chain. The Offset in a Pointer is not usually dynamic, meaning it will always be the same, but the Offset will not necessarily be the same for all Pointers (which it wasn't for D2). There are cases where the Offset could possibly be dynamic, in which case you are really going to have to do some work. :D

In the case of D2, there were 3 dynamic Pointers and a Static Pointer which I had to find that led me to the values I wanted. When I got to the last Pointer, I added in the user entered value to determine which address was read. Here is a visual example of how this works:

Static Pointer + Offset --> Pointer 1 + Offset --> Pointer 2 + Offset --> Pointer 3 + Offset + User Input --> Value

That is the easy part. ;)

The hard part is finding these Pointers. There are tools out there that help you find these Pointers. Cheat Engine is one, but tools like this don't work well in situations like you will encounter in D2, unless you want to inject a .dll or run a code cave (both of which would be detected by Battle.net). If you want to hack MineSweeper, it would work great though. :D

In order to get the addresses I needed in D2, I had to use a debugger. Specifically I used Ollydbg. In order to use a debugger to do this you will need some experience with Assembly Language Programming. Basic knowledge of Windows API programming would also be helpful. If you are interested in learning this I would suggest using Google and searching the net for articles and tutorials on this stuff. There is no way I, or anyone else, can tell you everything you would need to know to be able to do this for every instance of every program. You must learn the basics from articles and tutorials, then build on them by using what you know to figure out other things, and usually learning as you go.

This is basically what you would call "hacking". There are some people that will share some of this knowledge, but you will not likely get any "supreme" hacking knowledge that almost nobody else knows because anyone who has it probably isn't going to readily share it (like a dupe method for D2). I am by no means what you would call a veteran hacker, I'm just a newbie. So go search the web if you want to learn how to do this, that's what I had to do. I spent a lot of time reading and doing trial and error to learn the basic hacking knowledge I have. I suggest you do the same if you want to know how to do this.

If you can find a "Learn to Hack Anything in 2 Weeks" book, let me know. :P

Nomad :evil:


Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

this is a nice comment^^

thank you, now i understand the basics :D

how it works, now i need to know whats dllstruct think is for^^

thx for : - found by Busti

:D - > <3

got icq ? or msn ?

Edited by Busti

My UDF's : Startet on : 06.06.2006_CaseSearchOrReplaceStr();~> Searches OR Replaces a String,;~> With or Without Casesensivity

Share this post


Link to post
Share on other sites

this is a nice comment^^

thank you, now i understand the basics :D

how it works, now i need to know whats dllstruct think is for^^

thx for : - found by Busti

:P - > <3

got icq ? or msn ?

The help menu for AutoIt beta tells you everything you need to know. If you still don't understand it then you need to learn some basic C or C++ programming. Trying to explain how they work would take me quite a while, especially if you have little or no C/C++ programming experience.

This is a very handy link. You can learn C++, and many other languages here very easily. The tutorials are written as if you have never programmed anything in your life.

Look Here

I even use it sometimes, which is why I have it. :D

Go and absorb,

Nomad ;)


Share this post


Link to post
Share on other sites

i read help file 10000000000000 times :D but still hard too understand, again, have you any instant messanger ? i think we can chatt better :D


My UDF's : Startet on : 06.06.2006_CaseSearchOrReplaceStr();~> Searches OR Replaces a String,;~> With or Without Casesensivity

Share this post


Link to post
Share on other sites

i read help file 10000000000000 times :D but still hard too understand, again, have you any instant messanger ? i think we can chatt better :P

I'm sorry, but I don't have the time to try and explain it all to you, I already provided you with more than enough info as well as a link to a place to get more. It takes a high level of problem solving abilities to learn this stuff, you either have what it takes or you don't. I provided this script to help those that already know how to use it, not to get a lot of questions about how to use it, or what makes it work. There is a forum here to support questions like you are asking.

This is not a general support forum. If you have any more questions that are going to require a detailed response, please direct them to the proper forum.

Nomad :D


Share this post


Link to post
Share on other sites

#12 ·  Posted (edited)

i dont wanna know thinks, i wanna start a new project, thats why i want icq/msn :D

and i dont wanna make it alone

Edited by Busti

My UDF's : Startet on : 06.06.2006_CaseSearchOrReplaceStr();~> Searches OR Replaces a String,;~> With or Without Casesensivity

Share this post


Link to post
Share on other sites

i dont wanna know thinks, i wanna start a new project, thats why i want icq/msn :D

and i dont wanna make it alone

I don't have the time to explain all of this to you because I am working on a project of my own, which also means I don't have the time to help you with a project either...


Share this post


Link to post
Share on other sites

#14 ·  Posted (edited)

Edit : Doh... I did it again (posting in support this time)... somehow replying is intuitive... at least, the forum software is written that way.

Edited by Fuhrmanator

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0