Last active
February 11, 2018 16:12
-
-
Save zorgiepoo/5f769893ad2a7f58a747 to your computer and use it in GitHub Desktop.
Game speed hack prototype; still WIP
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#Game Speed Hack | |
#Increase x86-64 game by 2x by overriding mach_absolute_time | |
#May not work on games that call gettimeofday or something else instead | |
#May not work on games that don't call a time function at all (these areee badddd) | |
#May also not work if the function is referenced in more than one executable image (eg, local library) | |
#This is not very robust | |
from bitslicer import VirtualMemoryError, DebuggerError | |
import vmprot | |
SPEED_MULTIPLIER = 2.0 | |
class Script(object): | |
def __init__(self): | |
allocationSize = 4096 | |
self.address = vm.allocate(allocationSize) | |
vm.protect(self.address, allocationSize, vmprot.ALL) | |
vm.writeBytes(self.address, b'\x90' * allocationSize) | |
offsetToStartCode = 0x70 | |
machAbsoluteTimeAddress = debug.findSymbol("mach_absolute_time", "/libsystem_kernel.dylib") | |
##this is the following C code we want to create in asm## | |
# volatile double gSpeedMultiplier = 2.0; | |
# | |
# volatile uint8_t gInitializedMachAbsoluteTime; | |
# volatile uint64_t gMachAbsoluteBaseTime; | |
# volatile uint64_t gMachAbsoluteStartTime; | |
# volatile uint64_t gMachAbsoluteLastTime; | |
# uint64_t my_mach_absolute_time(void) | |
# { | |
# uint64_t result; | |
# uint64_t currentTime = mach_absolute_time(); | |
# | |
# if (!gInitializedMachAbsoluteTime) | |
# { | |
# gInitializedMachAbsoluteTime = 1; | |
# gMachAbsoluteBaseTime = currentTime; | |
# gMachAbsoluteStartTime = (gMachAbsoluteLastTime != 0) ? gMachAbsoluteLastTime : currentTime; | |
# result = gMachAbsoluteStartTime; | |
# } | |
# else | |
# { | |
# result = (uint64_t)(gMachAbsoluteStartTime + (currentTime - gMachAbsoluteBaseTime) * gSpeedMultiplier); | |
# } | |
# | |
# gMachAbsoluteLastTime = result; | |
# | |
# return result; | |
# } | |
self.initializedAddress = self.address | |
self.speedMultiplierAddress = self.address + 0x8 | |
baseTimeAddress = self.address + 0x10 | |
lastTimeAddress = self.address + 0x18 | |
startTimeAddress = self.address + 0x20 | |
label1Address = self.address + 0x30 | |
label2Address = self.address + 0x40 | |
label3Address = self.address + 0x50 | |
#_gInitializedMachAbsoluteTime | |
vm.writeUInt64(self.initializedAddress, 0x0) | |
#_gSpeedMultiplier | |
vm.writeDouble(self.speedMultiplierAddress, SPEED_MULTIPLIER) | |
#_gMachAbsoluteBaseTime | |
vm.writeUInt64(baseTimeAddress, 0) | |
#_gMachAbsoluteLastTime | |
vm.writeUInt64(lastTimeAddress, 0) | |
#_gMachAbsoluteStartTime | |
vm.writeBytes(startTimeAddress, b'\x00' * 0x10) | |
#L1 | |
vm.writeUInt64(label1Address, 0x4530000043300000) | |
vm.writeUInt64(label1Address + 0x8, 0x0) | |
#L2 | |
vm.writeUInt64(label2Address, 0x4330000000000000) | |
vm.writeBytes(label2Address + 0x8, b'\x00' * 6 + b'\x30\x45') | |
#L3 | |
vm.writeUInt64(label3Address, 0x43e0000000000000) | |
code = "\n".join([ | |
"push rbp", | |
"mov rbp, rsp", | |
"sub rsp, 0x20", | |
"mov rax, qword %d" % (machAbsoluteTimeAddress), | |
"call rax", | |
"mov rcx, qword %d" % (self.initializedAddress), | |
"mov [rbp-0x10], rax", | |
"mov dl, [rcx]", | |
"cmp dl, 0x0", | |
"jnz J1", | |
"mov rax, qword %d" % (lastTimeAddress), | |
"mov rcx, qword %d" % (baseTimeAddress), | |
"mov rdx, qword %d" % (self.initializedAddress), | |
"mov byte [rdx], 0x1", | |
"mov rdx, [rbp-0x10]", | |
"mov [rcx], rdx", | |
"mov rax, [rax]", | |
"cmp rax, 0x0", | |
"jz J2", | |
"mov rax, qword %d" % (lastTimeAddress), | |
"mov rax, [rax]", | |
"mov [rbp-0x18], rax", | |
"jmp J3", | |
"J2:", | |
"mov rax, [rbp-0x10]", | |
"mov [rbp-0x18], rax", | |
"J3:", | |
"mov rax, [rbp-0x18]", | |
"mov rcx, qword %d" % (startTimeAddress), | |
"mov [rcx], rax", | |
"mov rax, [rcx]", | |
"mov [rbp-0x8], rax", | |
"jmp J4", | |
"J1:", | |
"mov rax, %d" % (startTimeAddress), | |
"movq xmm0, [rax]", | |
"mov rax, qword %d" % (label1Address), | |
"movaps xmm1, oword [rax]", | |
"punpckldq xmm0, xmm1", | |
"mov rax, qword %d" % (label2Address), | |
"movapd xmm2, [rax]", | |
"subpd xmm0, xmm2", | |
"haddpd xmm0, xmm0", | |
"mov rax, [rbp-0x10]", | |
"mov rcx, qword %d" % (baseTimeAddress), | |
"mov rcx, [rcx]", | |
"sub rax, rcx", | |
"movd xmm3, rax", | |
"punpckldq xmm3, xmm1", | |
"subpd xmm3, xmm2", | |
"haddpd xmm3, xmm3", | |
"mov rax, qword %d" % (self.speedMultiplierAddress), | |
"movsd xmm1, [rax]", | |
"mulsd xmm3, xmm1", | |
"addsd xmm0, xmm3", | |
"mov rax, qword %d" % (label3Address), | |
"movsd xmm1, [rax]", | |
"movaps xmm2, xmm0", | |
"subsd xmm2, xmm1", | |
"cvttsd2si rax, xmm2", | |
"mov rcx, 0x8000000000000000", | |
"xor rax, rcx", | |
"cvttsd2si rcx, xmm0", | |
"ucomisd xmm0, xmm1", | |
"cmovb rax, rcx", | |
"mov [rbp-0x8], rax", | |
"J4:", | |
"mov rax, qword %d" % (lastTimeAddress), | |
"mov rcx, [rbp-0x8]", | |
"mov [rax], rcx", | |
"mov rax, [rbp-0x8]", | |
"add rsp, 0x20", | |
"pop rbp", | |
"ret" | |
]) | |
data = debug.assemble(code, self.address + offsetToStartCode) | |
vm.writeBytes(self.address + offsetToStartCode, data) | |
self.stubAddress = debug.findSymbol("DYLD-STUB$$mach_absolute_time") | |
# debug.log(hex(self.address)) | |
# debug.log(hex(self.address + offsetToStartCode)) | |
# debug.log(hex(self.stubAddress)) | |
vm.pause() | |
stubSize = 0x6 | |
vm.protect(self.stubAddress, stubSize, vmprot.ALL) | |
vm.writeBytes(self.stubAddress, debug.assemble("jmp %d\nnop" % (self.address + offsetToStartCode), self.stubAddress)) | |
vm.protect(self.stubAddress, stubSize, vmprot.READ | vmprot.EXECUTE) | |
vm.unpause() | |
def finish(self): | |
vm.pause() | |
vm.writeUInt8(self.initializedAddress, 0x0) | |
vm.writeDouble(self.speedMultiplierAddress, 1.0) | |
vm.unpause() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
How exactly do you tell it which process to target?