I study . correct me .
#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()