Copy a single register...
Code:
Public Function GetRegisterOnce(ByVal sourceLoc As IntPtr, ByVal register As CpuRegister) As IntPtr
Dim _codeCaveStartLoc As IntPtr = Malloc(200) 'in wow.exe ram, used to store (then run) bytecode. todo: auto-sized
Dim _codeCaveCode(0) As Byte ' stores bytecode to inject into process
Dim _origAsmLoc As IntPtr = _codeCaveStartLoc.ToInt32 + 100 'executable's orig. code copied here (8 bytes)
Dim _rtnValueLoc As IntPtr = _codeCaveStartLoc.ToInt32 + 175 'where our asm code copies the register to
Dim _origProcessByteCode() As Byte = ReadBytes(sourceLoc, 8) 'orig. wow.exe code (must be restored by codecave code)
WriteBytes(_origAsmLoc, _origProcessByteCode)
'Create codeCave byte code (copy,cleanup,return)
'copy register to our dump location
Dim registerAsString As String = System.Enum.GetName(GetType(CpuRegister), register) 'awk
Dim sb As New System.Text.StringBuilder
With sb
'save registers (that I use) to avoid corrupting stack
.AppendLine("push eax")
.AppendLine("push ebx")
.AppendLine("push edx")
'copy our rtnValueLoc to a register
.AppendLine("mov eax, " & _rtnValueLoc.ToInt32.ToString)
'copy register into the [value] at rtnValueLoc
.AppendLine("mov [eax], " & registerAsString) 'the magic happens right here
'clean-up
.AppendLine("mov eax, " & sourceLoc.ToInt32.ToString)
.AppendLine("mov ebx, " & _origAsmLoc.ToInt32.ToString)
.AppendLine("mov edx, [ebx]") 'copy 4 bytes from _origAsmLoc to exe source_loc
.AppendLine("mov [eax], edx") ' ie. unpatch using exe's orig source code
.AppendLine("add ebx, 4")
.AppendLine("add eax, 4")
.AppendLine("mov edx, [ebx]") 'copy next/last 4 bytes back into wow.exe
.AppendLine("mov [eax], edx") '
.AppendLine("pop edx") 'pop order is important. duh.
.AppendLine("pop ebx")
.AppendLine("pop eax")
End With
Dim _individualAsmStrings() As String = Split(sb.ToString, Environment.NewLine)
If _individualAsmStrings(_individualAsmStrings.Length - 1) = "" Then ReDim Preserve _individualAsmStrings(_individualAsmStrings.Length - 2) 'chop off empty string: last call should use ASM.Append() Not AppendLine() ? works.
Dim _cdc() As Byte 'codecave bytecode, except 5 bytes for a JMP command.
_cdc = GetByteCode(_individualAsmStrings)
Dim _jmpAsm(4) As Byte ' hand crafted JMP command : instead of using managed_fasm.assemble("JMP address")..Educational.
_jmpAsm(0) = &HE9 'opcode for Relative jump
ReDim _codeCaveCode(_cdc.Length - 1 + 5) '5 = _jmpAsm.Length in bytes, 'E9' + 4 byte ram address
Dim _bts() As Byte = BitConverter.GetBytes(sourceLoc.ToInt32 - _codeCaveStartLoc.ToInt32 - _codeCaveCode.Length) 'address where codecave jmps back to. (ie. sourceLoc, but relative* because I use 'E9' for JMP not 'FF') !!!
_bts.Reverse() 'endianness of bytecode
Array.Copy(_bts, 0, _jmpAsm, 1, 4) 'copy the 4 byte address into the asm jmp command
Array.Copy(_cdc, _codeCaveCode, _cdc.Length) 'copy the codecavecode(w/o jmp) to array
Array.Copy(_jmpAsm, 0, _codeCaveCode, _codeCaveCode.Length - 5, 5) 'copy jmp command to end of array
WriteBytes(_codeCaveStartLoc, _codeCaveCode) 'write the bytecode (100% complete now) into process's ram.
''Write Jmp command to sourceLoc. ie. WILL make it re-route
_bts = BitConverter.GetBytes(_codeCaveStartLoc.ToInt32 - (sourceLoc.ToInt32 + 5)) 'address of beginning of codecave. +5 because in asm, JMP is relative* to the NEXT instruction. Jmp is 5 bytes long.
_bts.Reverse() 'indianness of byte code
Array.Copy(_bts, 0, _jmpAsm, 1, 4) '_jmpAsm is now complete, again.
Dim scanStartTime As DateTime = Date.Now
Dim scanTimeLapse As TimeSpan
'enable ram to be written to
Dim _origAccessRights As UInt32 = 0
Dim _mbi As MEMORY_BASIC_INFORMATION
VirtualQueryEx(_targetProcessHandle, sourceLoc, _mbi, _mbiSize)
If Not (_mbi.Protect And MemoryAllocationProtectionType.PAGE_EXECUTE_READWRITE) Then
'change rights
If Not VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, MemoryAllocationProtectionType.PAGE_EXECUTE_READWRITE, _origAccessRights) Then
modPublic.DoOutput("CodeCave::CopyRegisterOnce::VirtualProtectEx fail 0x" & sourceLoc.ToString("X"))
Return IntPtr.Zero 'can't write to this memory?
End If
End If
'if we get here, orig perms. were exec_r_w or VirtualProtect worked
WriteBytes(sourceLoc, _jmpAsm) ' .Patch()
'modPublic.DoOutput("scanning for rtn value...")
Dim _origJumpLocCode As UInt64 = BitConverter.ToUInt64(_origProcessByteCode, 0) 'because orig asm is only 8 bytes i used int64. should use byte array.
Do Until ReadUInt64(sourceLoc) = _origJumpLocCode 'do until the codecave unpatches itsself!(ie. orig code has been restored) nifty.
scanTimeLapse = Date.Now.Subtract(scanStartTime)
If scanTimeLapse.TotalSeconds > 10 Then
'we need to manually put the source Bcode back
WriteBytes(sourceLoc, _origProcessByteCode)
If _origAccessRights <> 0 Then
'we changed rights, change them back.
VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, _origAccessRights, New UInt32)
End If
modPublic.DoOutput("Time limit exceeded. 10s")
Return IntPtr.Zero ' wow.exe code never got called. or other asm/codecavecode error?...
End If
Loop
'if we get here, success!
Dim _rtnPtr As IntPtr = ReadIntPtr(_rtnValueLoc) ' == register value !
'modPublic.DoOutput("success: val=" & _rtnPtr.ToString("x"))
'free mem allocated for codecave inside wow
VirtualFreeEx(_targetProcessHandle, _codeCaveStartLoc, 200, MemoryAllocationState.Decommit)
'restore rights?
If _origAccessRights <> 0 Then
VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, _origAccessRights, New Int32)
End If
Return _rtnPtr
End Function
Copy all registers (well, most of the big ones)
Code:
Public Function GetRegistersAllOnce(ByVal sourceLoc As IntPtr) As CPU_REGISTERS
Dim _rtnRegisters As CPU_REGISTERS
Dim _codeCaveStartLoc As IntPtr = Malloc(200)
Dim _codeCaveCode() As Byte ' stores bytecode to inject into process
Dim _origAsmLoc As IntPtr = _codeCaveStartLoc.ToInt32 + 190 'code-cave's orig. code copied here (8 bytes)
Dim _rtnValueLoc As IntPtr = _codeCaveStartLoc.ToInt32 + 100 'where our asm code copies the register
Dim _origProcessByteCode() As Byte = ReadBytes(sourceLoc, 8) 'original process asm, which we replace w/ JMP
WriteBytes(_origAsmLoc, _origProcessByteCode)
'copy the register to our dump location
Dim sb As New System.Text.StringBuilder
With sb
.AppendLine("push eax")
.AppendLine("push edx")
.AppendLine("mov edx, " & _rtnValueLoc.ToInt32.ToString) 'start of rtn value loc in memory
'copy registers into rtnValueLoc demp are
.AppendLine("mov [edx], eax") 'copy eax
.AppendLine("add edx, 4")
.AppendLine("mov [edx], ebx") 'copy ebx
.AppendLine("add edx, 4")
.AppendLine("mov [edx], ecx") 'copy ecx
.AppendLine("add edx, 4")
.AppendLine("mov eax, edx") 'switch register being used as the place holder
.AppendLine("pop edx")
.AppendLine("mov [eax], edx") 'copy edx
.AppendLine("add eax, 4")
.AppendLine("mov [eax], edi") 'copy esi
.AppendLine("add eax, 4")
.AppendLine("mov [eax], esi") 'copy edi
.AppendLine("add eax, 4")
.AppendLine("mov [eax], ebp") 'copy ebp
.AppendLine("add eax, 4")
.AppendLine("mov [eax], esp") 'copy esp
'clean-up
.AppendLine("push ebx")
.AppendLine("push edx")
.AppendLine("mov eax, " & sourceLoc.ToInt32.ToString)
.AppendLine("mov ebx, " & _origAsmLoc.ToInt32.ToString)
.AppendLine("mov edx, [ebx]")
.AppendLine("mov [eax], edx")
.AppendLine("add ebx, 4")
.AppendLine("add eax, 4")
.AppendLine("mov edx, [ebx]")
.AppendLine("mov [eax], edx")
.AppendLine("pop edx")
.AppendLine("pop ebx")
.AppendLine("pop eax")
End With
Dim _individualAsmStrings() As String = Split(sb.ToString, Environment.NewLine)
Dim _cdc() As Byte 'codecave bytecode, minus 5 bytes for the JMP command.
Dim _jmpAsm(4) As Byte ' hand crafted JMP command : instead of using managed_fasm.assemble("JMP offset")..
_jmpAsm(0) = &HE9 'opcode for relative jump
If _individualAsmStrings(_individualAsmStrings.Length - 1) = "" Then ReDim Preserve _individualAsmStrings(_individualAsmStrings.Length - 2) 'chop off empty string at end..
_cdc = GetByteCode(_individualAsmStrings)
ReDim _codeCaveCode(_cdc.Length - 1 + 5) '5 = _jmpAsm.Length in bytes, 'E9' + 4 bytes. -1 for explicitness
Dim _bts() As Byte = BitConverter.GetBytes(sourceLoc.ToInt32 - _codeCaveStartLoc.ToInt32 - _codeCaveCode.Length) 'address where codecave jmps back to. (ie. sourceLoc, but relative because I use 'E9' for JMP not 'FF')
_bts.Reverse() ' endianness
Array.Copy(_bts, 0, _jmpAsm, 1, 4) 'copy the 4 byte address into the asm command
Array.Copy(_cdc, _codeCaveCode, _cdc.Length) 'copy the codecavecode(w/o jmp) to Array()
Array.Copy(_jmpAsm, 0, _codeCaveCode, _codeCaveCode.Length - 5, 5) 'copy asm command to end of Array()
WriteBytes(_codeCaveStartLoc, _codeCaveCode) 'write the bytecode (100% complete now) into process's ram.
''Write Jmp command to sourceLoc
_bts = BitConverter.GetBytes(_codeCaveStartLoc.ToInt32 - (sourceLoc.ToInt32 + 5)) 'address of beginning of codecave. +5 because in asm, JMP is relative to the NEXT instruction. Jmp is 5 bytes long.
_bts.Reverse() 'indian
Array.Copy(_bts, 0, _jmpAsm, 1, 4)
Dim scanStartTime As DateTime = Date.Now
Dim scanTimeLapse As TimeSpan
'enable ram to be written to
Dim _origAccessRights As UInt32 = 0
Dim _mbi As MEMORY_BASIC_INFORMATION
VirtualQueryEx(_targetProcessHandle, sourceLoc, _mbi, _mbiSize)
If Not (_mbi.Protect And MemoryAllocationProtectionType.PAGE_EXECUTE_READWRITE) Then
'change rights
If Not VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, MemoryAllocationProtectionType.PAGE_EXECUTE_READWRITE, _origAccessRights) Then
modPublic.DoOutput("CodeCave::CopyRegisterOnce::VirtualProtectEx fail 0x" & sourceLoc.ToString("X"))
Return New CPU_REGISTERS 'can't write to this memory?
End If
End If
'if we get here, orig perms. were exec_r_w or VirtualProtect worked
DoOutput("Patching 0x" & sourceLoc.ToString("X"))
WriteBytes(sourceLoc, _jmpAsm) ' .Inject() :: Write JMP command to process code --next time it's ran, our codecave gets executed!
modPublic.DoOutput("scanning for rtn value...")
Dim _origJumpLocCode As UInt64 = BitConverter.ToUInt64(_origProcessByteCode, 0)
Do Until ReadUInt64(sourceLoc) = _origJumpLocCode
scanTimeLapse = Date.Now.Subtract(scanStartTime)
If scanTimeLapse.TotalSeconds > 10 Then
'we need to manually put the source Bcode back
WriteBytes(sourceLoc, _origProcessByteCode)
If _origAccessRights Then
'we changed rights, change them back.
VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, _origAccessRights, New UInt32)
End If
DoOutput("ASM:CopyRegistersALL() Failed to be run.")
Return New CPU_REGISTERS
End If
Loop
'if we get here, success!
Dim _rtnBytes() As Byte = ReadBytes(_rtnValueLoc, 32)
_rtnRegisters.eax = BitConverter.ToUInt32(_rtnBytes, 0) '' sloppy?
_rtnRegisters.ebx = BitConverter.ToUInt32(_rtnBytes, 4)
_rtnRegisters.ecx = BitConverter.ToUInt32(_rtnBytes, 8)
_rtnRegisters.edx = BitConverter.ToUInt32(_rtnBytes, 12)
_rtnRegisters.edi = BitConverter.ToUInt32(_rtnBytes, 16)
_rtnRegisters.esi = BitConverter.ToUInt32(_rtnBytes, 20)
_rtnRegisters.ebp = BitConverter.ToUInt32(_rtnBytes, 24)
_rtnRegisters.esp = BitConverter.ToUInt32(_rtnBytes, 28)
'free VirtualAllocEx memory
VirtualFreeEx(_targetProcessHandle, _codeCaveStartLoc, 200, MemoryAllocationState.Decommit)
'restore rights?
If _origAccessRights Then
VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, _origAccessRights, New Int32)
End If
Return _rtnRegisters
End Function
//structs/enums
Code:
Public Structure CPU_REGISTERS
Dim eax As UInt32
Dim ebx As UInt32
Dim ecx As UInt32
Dim edx As UInt32
Dim edi As UInt32
Dim esi As UInt32
Dim ebp As UInt32
Dim esp As UInt32
End Structure
Public Enum CpuRegister As UInt32
eax = 0
ebx
ecx
edx
edi
esi
ebp
esp
End Enum