Forged
09-23-2005, 05:37 PM
Tutorial Information
Author: Enmitix
Game/Version: Warcraft III, with or without Frozen Throne expansion, all versions
Difficulty: Intermediate, knowledge of the Win32 API would be nice
Tools used: ArtMoney (http://www.securegamers.com/downloads/Sources/artmoney710eng.exe) or similar memory-editor, any programming language (We'll be using VB for this example)
Introduction
When someone starts out wanting to hack, there are many new concepts for that person to learn. One such concept is Dynamic Memory Allocation, or DMA, which I will attempt to explain today and apply it to a hack such as the namespoofer.
DMA
DMA, Dynamic Memory Allocation, can be both a curse and a blessing. Memory addresses are dynamically appointed to methods within the process as they are being started for the first time. Because of this, the addresses are almost always at a different location and makes it impossible to write a hack for it that simply writes to one static location. The blessing? Because the pointer to it will always point to the same location-range and it's relative offset, changing the hard-coded data, such as patching the game or getting a different version, does not always change the DMA addressing and allows your code to still work. This is why it's so easy to make a namespoofer or a cd-key grabber to work for ALL versions of Warcraft III.
The Hack
Alright, let's get to it. First thing you do is open Warcraft III (Yeah, any version will work). Connect to Battle.net. Open ArtMoney and select process 'Warcraft III'. Do a text-search for your name, it should return a whole bunch of addresses. Now there are ways to figure out exactly which one Battle.net uses for what, but the quick and dirty way to do it is to change each instance in your name, in ArtMoney, to something else. For example, if your name was 'BobotheClown' and it returned 8 instances, change the first one to 'Bobo1', second one to 'Bobo2', etc, all the way up to 'Bobo8'. Return to Warcraft, and join a game. Your name now -should- be changed to one of the 'Bobo#' names. Check ArtMoney, record the address of the 'Bobo#' that changed, quit Warcraft, repeat.
Since this uses DMA, you will have to repeat several times, always recording the address of the name that changed. Once you've done this a couple of times, look at the addresses and try to figure out some sort of common sequence to them. In case of your Battle.net name, for example, the address will always end in (Hex)02B4.
So now that you kinda know where your name is stored, you're left with one problem. Since names will always be different you can search every 0x####02B4 for it. So what do you do? Well, another trick to 'defeating' DMA is to search out signature data around your target data, something that will never change. If you do some searching around, you'll notice that about 32bytes (or, 0x20 bytes in hex) after the addresses where your name is stored, there will always be ASCII value 'PX3W' or '3RAW' depending on if you're using regular Warcraft III or have the Expansion installed.
So instead of looking for your name at 0x####02B4, you should try looking for 'PX3W' or '3RAW' 0x20 bytes later, or at 0x####02D4.
Since these last 4 hex-digits (02D4) never change, it's now easy to figure out your name using a little loop that goes through the memory
(VB Code):
'---Declarations:
Option Explicit
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal Classname As String, ByVal WindowName As String) As Long
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, ByVal lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Long, ByVal lpBaseAddress As Any, ByRef lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Sub GetSystemInfo Lib "kernel32" (lpSystemInfo As SYSTEM_INFO)
Const PROCESS_ALL_ACCESS = &H1F0FFF
Const MEM_PRIVATE& = &H20000
Const MEM_COMMIT& = &H1000
Private Type SYSTEM_INFO
dwOemID As Long
dwPageSize As Long
lpMinimumApplicationAddress As Long
lpMaximumApplicationAddress As Long
dwActiveProcessorMask As Long
dwNumberOrfProcessors As Long
dwProcessorType As Long
dwAllocationGranularity As Long
wProcessorLevel As Integer
wProcessorRevision As Integer
End Type
'---Actual code for sub goes here:
Dim hwnd As Long, pID As Long, hProc As Long, si As SYSTEM_INFO
Dim Address as Long, vbuffer as long, result as long, nameAddress as long
hwnd = FindWindow("Warcraft III", vbNullString)
result = -1
If (hwnd) Then
Call GetWindowThreadProcessId(hwnd, pID)
hProc = OpenProcess(PROCESS_ALL_ACCESS, False, pID)
If (hProc) Then
Call GetSystemInfo(si)
'---Start address for loop here
Address = &H02D4
Do While result = -1 And Address < si.lpMaximumApplicationAddress
Call ReadProcessMemory(hProc, Address, vbuffer, 4, 0&)
If vbuffer = &H57335850 Then 'if result = '3RAW'...
result = Address
ElseIf vbuffer = &H33524157 Then'else if result = 'PX3W'...
result = Address
End If
Address = Address + &H10000
DoEvents
Loop
End If
End If
If result <> -1 then
nameAddress = result - &h20
msgbox "NAME STORED AT 0x" & hex(nameAddress)
else
msgbox "uh oh something went wrong, could not find address of name"
exit sub
End If
Try that, see if it finds the correct address of where your name is stored. I hope this code is kind of self-explanatory, I was never good at writing legible code :p
Anyways, now we know where the name is stored, it's simply a process of writing our new name to that address and we'll be spoofed. Since 15 bytes are allocated to the name, if the name name is less than 15 bytes, we need to write the remaining bytes with 0-bytes, and don't forget to close the handle after we're done. Let's try it:
dim i as Integer
Dim newName As String
newName = "EnmitixRocks"
For i = 0 To len(newName) - 1
WriteProcessMemory hProc, (nameAddress) + i, Asc(Mid(newName, i + 1, 1)), 1, 0&
Next i
For i = len(newName) To 14
WriteProcessMemory hProc, (nameAddress) + i, &H0, 1, 0&
Next i
Call CloseHandle(hProc)
And the new name is finally written to the memory. Switch back to Battle.net and try it out.
Other applications
Once all the information in this article is understood, one can apply it to different hacks that require the use of DMA. With this knowledge, it will be easy to make such hacks that allow you to grab your CD-Key, or the level of your hero. All this knowledge can also easily be applied to other games that make use of DMA.
Conclusion
This is the first tutorial I've ever written, I hope it's not too confusing. Since I'm not doing any more hacking for this game, I hope honest people (like, people that don't just blatantly rip other's code *cough* dankstoner *cough) will learn something from this and apply it to hacking themselves
Author: Enmitix
Game/Version: Warcraft III, with or without Frozen Throne expansion, all versions
Difficulty: Intermediate, knowledge of the Win32 API would be nice
Tools used: ArtMoney (http://www.securegamers.com/downloads/Sources/artmoney710eng.exe) or similar memory-editor, any programming language (We'll be using VB for this example)
Introduction
When someone starts out wanting to hack, there are many new concepts for that person to learn. One such concept is Dynamic Memory Allocation, or DMA, which I will attempt to explain today and apply it to a hack such as the namespoofer.
DMA
DMA, Dynamic Memory Allocation, can be both a curse and a blessing. Memory addresses are dynamically appointed to methods within the process as they are being started for the first time. Because of this, the addresses are almost always at a different location and makes it impossible to write a hack for it that simply writes to one static location. The blessing? Because the pointer to it will always point to the same location-range and it's relative offset, changing the hard-coded data, such as patching the game or getting a different version, does not always change the DMA addressing and allows your code to still work. This is why it's so easy to make a namespoofer or a cd-key grabber to work for ALL versions of Warcraft III.
The Hack
Alright, let's get to it. First thing you do is open Warcraft III (Yeah, any version will work). Connect to Battle.net. Open ArtMoney and select process 'Warcraft III'. Do a text-search for your name, it should return a whole bunch of addresses. Now there are ways to figure out exactly which one Battle.net uses for what, but the quick and dirty way to do it is to change each instance in your name, in ArtMoney, to something else. For example, if your name was 'BobotheClown' and it returned 8 instances, change the first one to 'Bobo1', second one to 'Bobo2', etc, all the way up to 'Bobo8'. Return to Warcraft, and join a game. Your name now -should- be changed to one of the 'Bobo#' names. Check ArtMoney, record the address of the 'Bobo#' that changed, quit Warcraft, repeat.
Since this uses DMA, you will have to repeat several times, always recording the address of the name that changed. Once you've done this a couple of times, look at the addresses and try to figure out some sort of common sequence to them. In case of your Battle.net name, for example, the address will always end in (Hex)02B4.
So now that you kinda know where your name is stored, you're left with one problem. Since names will always be different you can search every 0x####02B4 for it. So what do you do? Well, another trick to 'defeating' DMA is to search out signature data around your target data, something that will never change. If you do some searching around, you'll notice that about 32bytes (or, 0x20 bytes in hex) after the addresses where your name is stored, there will always be ASCII value 'PX3W' or '3RAW' depending on if you're using regular Warcraft III or have the Expansion installed.
So instead of looking for your name at 0x####02B4, you should try looking for 'PX3W' or '3RAW' 0x20 bytes later, or at 0x####02D4.
Since these last 4 hex-digits (02D4) never change, it's now easy to figure out your name using a little loop that goes through the memory
(VB Code):
'---Declarations:
Option Explicit
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal Classname As String, ByVal WindowName As String) As Long
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, ByVal lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Long, ByVal lpBaseAddress As Any, ByRef lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Sub GetSystemInfo Lib "kernel32" (lpSystemInfo As SYSTEM_INFO)
Const PROCESS_ALL_ACCESS = &H1F0FFF
Const MEM_PRIVATE& = &H20000
Const MEM_COMMIT& = &H1000
Private Type SYSTEM_INFO
dwOemID As Long
dwPageSize As Long
lpMinimumApplicationAddress As Long
lpMaximumApplicationAddress As Long
dwActiveProcessorMask As Long
dwNumberOrfProcessors As Long
dwProcessorType As Long
dwAllocationGranularity As Long
wProcessorLevel As Integer
wProcessorRevision As Integer
End Type
'---Actual code for sub goes here:
Dim hwnd As Long, pID As Long, hProc As Long, si As SYSTEM_INFO
Dim Address as Long, vbuffer as long, result as long, nameAddress as long
hwnd = FindWindow("Warcraft III", vbNullString)
result = -1
If (hwnd) Then
Call GetWindowThreadProcessId(hwnd, pID)
hProc = OpenProcess(PROCESS_ALL_ACCESS, False, pID)
If (hProc) Then
Call GetSystemInfo(si)
'---Start address for loop here
Address = &H02D4
Do While result = -1 And Address < si.lpMaximumApplicationAddress
Call ReadProcessMemory(hProc, Address, vbuffer, 4, 0&)
If vbuffer = &H57335850 Then 'if result = '3RAW'...
result = Address
ElseIf vbuffer = &H33524157 Then'else if result = 'PX3W'...
result = Address
End If
Address = Address + &H10000
DoEvents
Loop
End If
End If
If result <> -1 then
nameAddress = result - &h20
msgbox "NAME STORED AT 0x" & hex(nameAddress)
else
msgbox "uh oh something went wrong, could not find address of name"
exit sub
End If
Try that, see if it finds the correct address of where your name is stored. I hope this code is kind of self-explanatory, I was never good at writing legible code :p
Anyways, now we know where the name is stored, it's simply a process of writing our new name to that address and we'll be spoofed. Since 15 bytes are allocated to the name, if the name name is less than 15 bytes, we need to write the remaining bytes with 0-bytes, and don't forget to close the handle after we're done. Let's try it:
dim i as Integer
Dim newName As String
newName = "EnmitixRocks"
For i = 0 To len(newName) - 1
WriteProcessMemory hProc, (nameAddress) + i, Asc(Mid(newName, i + 1, 1)), 1, 0&
Next i
For i = len(newName) To 14
WriteProcessMemory hProc, (nameAddress) + i, &H0, 1, 0&
Next i
Call CloseHandle(hProc)
And the new name is finally written to the memory. Switch back to Battle.net and try it out.
Other applications
Once all the information in this article is understood, one can apply it to different hacks that require the use of DMA. With this knowledge, it will be easy to make such hacks that allow you to grab your CD-Key, or the level of your hero. All this knowledge can also easily be applied to other games that make use of DMA.
Conclusion
This is the first tutorial I've ever written, I hope it's not too confusing. Since I'm not doing any more hacking for this game, I hope honest people (like, people that don't just blatantly rip other's code *cough* dankstoner *cough) will learn something from this and apply it to hacking themselves