手潮了,长时间不做逆向水平就会下降。再次记录一次逆向手段。这次争取写的更全面一些。之前的CSGO只是在windows上的一次简单实践,只是完成了glow esp。
这次在Mac OS上进行实践。
目标:血量、子弹、弹夹数的修改。TODO:透视、auto aim
手段:找到血量、子弹等属性的内存地址,通过这些内存地址反向推理player对象或者结构体的base address和属性的offset。
知识:内存搜索、mach格式、lldb调试手段、AT&T指令集、ALSR(Address Space Layout Randomization)知识点请自行Google it!
工具:Bit-Slicer、lldb
步骤:
1. 打开游戏,建立游戏,通过Bit-Slicer找到子弹的地址 0x10200FF68
2. 找到游戏的pid: ps aux | grep -i assaultcube ·pid 为 40880·
3. 使用lldb调试器,attach pid:process attach --pid 40880
4. 通过Bit-Slicer找到血量地址 0x10200F710,可以用炸弹或者别人打你一枪,只要不爆头哈哈。设置观察点命令请看第4条# 血量变成889 Watchpoint 1 hit: old value: 889 new value: 889 Process 55018 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = watchpoint 1 frame #0: 0x000000010002c100 assaultcube`___lldb_unnamed_symbol497$$assaultcube + 688 assaultcube`___lldb_unnamed_symbol497$$assaultcube: -> 0x10002c100 <+688>: subl %esi, %r13d 0x10002c103 <+691>: subl %r13d, 0x110(%r12) 0x10002c10b <+699>: cmpq %r12, %r14 0x10002c10e <+702>: jne 0x10002c1b8 ; <+872> Target 0: (assaultcube) stopped. (lldb) register read General Purpose Registers: rax = 0x0000000000000000 rbx = 0x0000000000000001 rcx = 0x0000000000000003 rdx = 0x0000000000000000 rdi = 0x0000000000000000 rsi = 0x0000000000000000 rbp = 0x00007ffeefbff510 rsp = 0x00007ffeefbff4c0 r8 = 0x0000000000000000 r9 = 0x000000000000002c r10 = 0x0000000000000003 r11 = 0x0000000000000000 r12 = 0x000000010200f600 r13 = 0x000000000000002c r14 = 0x000000010200f600 r15 = 0x0000000103bd0a00 rip = 0x000000010002c100 assaultcube`___lldb_unnamed_symbol497$$assaultcube + 688 rflags = 0x0000000000200246 cs = 0x000000000000002b fs = 0x0000000000000000 gs = 0x0000000000000000
通过AT&T指令集,不懂的同学自行学习,这里不展开说,只说结论:
0x10002c103 <+691>: subl %r13d, 0x110(%r12)
这个指令集是 ($r12的地址 + 0x110)指向的值其实就是血量,而$r12其实就是player结构体的地址,通过读取寄存器可以找到 $r12 = 0x10200f600
你可以通过lldb确认一下刚才的指令
(lldb) p/x 0x000000010200f600 + 0x110 (long) $6 = 0x000000010200f710 (lldb) memory read 0x000000010200f710 0x10200f710: 79 03 00 00 00 00 00 00 06 00 00 00 06 00 00 00 y............... 0x10200f720: 06 00 00 00 00 00 00 00 01 00 00 00 46 00 00 00 ............F... (lldb) p/d 0x379 (int) $12 = 889 # 这里可以看到确实是血量
接下来简单了,可以使用vmmap命令,或者lldb找到内存的region
$ vmmap 55018 | grep "assaultcube$" Path: /Applications/AssaultCube.app/Contents/gamedata/assaultcube.app/Contents/MacOS/assaultcube __TEXT 100000000-10018c000 [ 1584K 1584K 4K 0K] r-x/rwx SM=COW /Applications/AssaultCube.app/Contents/gamedata/assaultcube.app/Contents/MacOS/assaultcube __LINKEDIT 1001d1000-1001d8000 [ 28K 28K 0K 0K] r--/rwx SM=COW /Applications/AssaultCube.app/Contents/gamedata/assaultcube.app/Contents/MacOS/assaultcube __DATA 10018c000-100193000 [ 28K 28K 28K 0K] rw-/rwx SM=COW /Applications/AssaultCube.app/Contents/gamedata/assaultcube.app/Contents/MacOS/assaultcube __DATA 100193000-1001d1000 [ 248K 248K 244K 0K] rw-/rwx SM=PRV /Applications/AssaultCube.app/Contents/gamedata/assaultcube.app/Contents/MacOS/assaultcube
__DATA段就是,另外一个方法:
(lldb) image dump sections assaultcube Sections for '/Applications/AssaultCube.app/Contents/gamedata/assaultcube.app/Contents/MacOS/assaultcube' (x86_64): SectID Type Load Address Perm File Off. File Size Flags Section Name ---------- ---------------- --------------------------------------- ---- ---------- ---------- ---------- ---------------------------- 0x00000100 container [0x0000000000000000-0x0000000100000000)* --- 0x00000000 0x00000000 0x00000000 assaultcube.__PAGEZERO 0x00000200 container [0x0000000100000000-0x000000010018c000) r-x 0x00000000 0x0018c000 0x00000000 assaultcube.__TEXT 0x00000001 code [0x0000000100001640-0x000000010013780c) r-x 0x00001640 0x001361cc 0x80000400 assaultcube.__TEXT.__text 0x00000002 code [0x000000010013780c-0x000000010013807c) r-x 0x0013780c 0x00000870 0x80000408 assaultcube.__TEXT.__stubs 0x00000003 code [0x000000010013807c-0x0000000100138e9c) r-x 0x0013807c 0x00000e20 0x80000400 assaultcube.__TEXT.__stub_helper 0x00000004 regular [0x0000000100138ea0-0x0000000100155ae4) r-x 0x00138ea0 0x0001cc44 0x00000000 assaultcube.__TEXT.__const 0x00000005 data-cstr [0x0000000100155af0-0x0000000100165b12) r-x 0x00155af0 0x00010022 0x00000002 assaultcube.__TEXT.__cstring 0x00000006 regular [0x0000000100165b14-0x000000010016a3bc) r-x 0x00165b14 0x000048a8 0x00000000 assaultcube.__TEXT.__gcc_except_tab 0x00000007 data-cstr [0x000000010016a3bc-0x000000010016a644) r-x 0x0016a3bc 0x00000288 0x00000002 assaultcube.__TEXT.__objc_methname 0x00000008 data-cstr [0x000000010016a644-0x000000010016a68c) r-x 0x0016a644 0x00000048 0x00000002 assaultcube.__TEXT.__objc_classname 0x00000009 data-cstr [0x000000010016a68c-0x000000010016a6c2) r-x 0x0016a68c 0x00000036 0x00000002 assaultcube.__TEXT.__objc_methtype 0x0000000a compact-unwind [0x000000010016a6c4-0x000000010016cd50) r-x 0x0016a6c4 0x0000268c 0x00000000 assaultcube.__TEXT.__unwind_info 0x0000000b eh-frame [0x000000010016cd50-0x000000010018bff8) r-x 0x0016cd50 0x0001f2a8 0x00000000 assaultcube.__TEXT.__eh_frame 0x00000300 container [0x000000010018c000-0x00000001001d1000) rw- 0x0018c000 0x00007000 0x00000000 assaultcube.__DATA 0x0000000c regular [0x000000010018c000-0x000000010018c028) rw- 0x0018c000 0x00000028 0x00000000 assaultcube.__DATA.__program_vars 0x0000000d data-ptrs [0x000000010018c028-0x000000010018c038) rw- 0x0018c028 0x00000010 0x00000006 assaultcube.__DATA.__nl_symbol_ptr 0x0000000e data-ptrs [0x000000010018c038-0x000000010018c0d0) rw- 0x0018c038 0x00000098 0x00000006 assaultcube.__DATA.__got 0x0000000f data-ptrs [0x000000010018c0d0-0x000000010018cc10) rw- 0x0018c0d0 0x00000b40 0x00000007 assaultcube.__DATA.__la_symbol_ptr 0x00000010 data-ptrs [0x000000010018cc10-0x000000010018cd68) rw- 0x0018cc10 0x00000158 0x00000009 assaultcube.__DATA.__mod_init_func 0x00000011 regular [0x000000010018cd70-0x000000010018e480) rw- 0x0018cd70 0x00001710 0x00000000 assaultcube.__DATA.__const 0x00000012 regular [0x000000010018e480-0x000000010018e488) rw- 0x0018e480 0x00000008 0x10000000 assaultcube.__DATA.__objc_nlclslist 0x00000013 regular [0x000000010018e488-0x000000010018e498) rw- 0x0018e488 0x00000010 0x00000000 assaultcube.__DATA.__objc_protolist 0x00000014 regular [0x000000010018e498-0x000000010018e4a0) rw- 0x0018e498 0x00000008 0x00000000 assaultcube.__DATA.__objc_imageinfo 0x00000015 data-ptrs [0x000000010018e4a0-0x000000010018e5e0) rw- 0x0018e4a0 0x00000140 0x00000000 assaultcube.__DATA.__objc_const 0x00000016 data-cstr-ptr [0x000000010018e5e0-0x000000010018e708) rw- 0x0018e5e0 0x00000128 0x10000005 assaultcube.__DATA.__objc_selrefs 0x00000017 regular [0x000000010018e708-0x000000010018e718) rw- 0x0018e708 0x00000010 0x00000000 assaultcube.__DATA.__objc_protorefs 0x00000018 data-ptrs [0x000000010018e718-0x000000010018e728) rw- 0x0018e718 0x00000010 0x10000000 assaultcube.__DATA.__objc_classrefs 0x00000019 data-ptrs [0x000000010018e728-0x000000010018e778) rw- 0x0018e728 0x00000050 0x00000000 assaultcube.__DATA.__objc_data 0x0000001a data [0x000000010018e780-0x0000000100192d28) rw- 0x0018e780 0x000045a8 0x00000000 assaultcube.__DATA.__data 0x0000001b zero-fill [0x0000000100192d30-0x00000001001bd142) rw- 0x00000000 0x00000000 0x00000001 assaultcube.__DATA.__common 0x0000001c zero-fill [0x00000001001bd150-0x00000001001d0e71) rw- 0x00000000 0x00000000 0x00000001 assaultcube.__DATA.__bss 0x00000400 container [0x00000001001d1000-0x00000001001d7adc) r-- 0x00193000 0x00006adc 0x00000000 assaultcube.__LINKEDIT
# 搜索刚才的基址0x10200f600,这个地址其实是alsr产生的运行实际地址 # 找到了固定的player的基址为0x1001abf08 # 那么血量的offset就是0x110 (lldb) memory find -e 0x10200f600 0x000000010018c000 0x00000001001d1000 data found at location: 0x1001abf08 0x1001abf08: 00 f6 00 02 01 00 00 00 f0 4d 2f 5d 01 00 00 00 .?......?M/].... 0x1001abf18: 10 00 00 00 04 00 00 00 d0 b8 04 00 d0 b8 04 00 ........и..и..
那么血量的offset就是0x110
4. 查找子弹的偏移量
(lldb) watchpoint set expression -- 0x10200FF68 Watchpoint created: Watchpoint 1: addr = 0x10200ff68 size = 8 state = enabled type = w new value: 998
998就是子弹数量
# 建立watchpoint观察点 (lldb) watchpoint modify -c '*(int*)0x10200FF68 < 998' # continue (lldb) c Process 40880 resuming
开一枪会小于998,命中观察点
# 开一枪后断点卡住,可以看到子弹变成997 Watchpoint 1 hit: old value: 998 new value: 997 Process 40880 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = watchpoint 1 frame #0: 0x0000000100103f71 assaultcube`___lldb_unnamed_symbol2400$$assaultcube + 529 assaultcube`___lldb_unnamed_symbol2400$$assaultcube: -> 0x100103f71 <+529>: movq 0x10(%r13), %rax 0x100103f75 <+533>: movb $0x1, %r15b 0x100103f78 <+536>: cmpq (%rbx), %rax 0x100103f7b <+539>: jne 0x10010401a ; <+698> Target 0: (assaultcube) stopped.
打印寄存器的列表
(lldb) register read General Purpose Registers: rax = 0x000000010200ff68 rbx = 0x00000001001abf08 # base address rcx = 0x000000010200ff90 rdx = 0x0000000000000000 rdi = 0x0000000000000001 rsi = 0x00000000000000dc rbp = 0x00007ffeefbffad0 rsp = 0x00007ffeefbffa60 r8 = 0x14d2082090214802 r9 = 0x0000000101900000 r10 = 0x0000000000000002 r11 = 0x00000000000000e5 r12 = 0x00007ffeefbffa88 r13 = 0x00000001018042b0 r14 = 0x00000000000bd06c r15 = 0x00007ffeefbffa98 rip = 0x0000000100103f71 assaultcube`___lldb_unnamed_symbol2400$$assaultcube + 529 rflags = 0x0000000000200202 cs = 0x000000000000002b fs = 0x0000000000000000 gs = 0x0000000000000000
# 通过$r13 + 0x10计算出来指针0x101304df0,然后找到指向的地址是0x10200f600,这个地址是运行时player的基址 # 下面通过血量来验证一下player的基址 (lldb) p/x 0x0000000101304de0 + 0x10 (long) $4 = 0x0000000101304df0 (lldb) memory read 0x0000000101304df0 0x101304df0: 00 f6 00 02 01 00 00 00 e0 0c 19 00 01 00 00 00 .?......?....... 0x101304e00: 40 f7 00 02 01 00 00 00 68 f7 00 02 01 00 00 00 @?......h?......
# 因此可以知道子弹的偏移地址: (lldb) p/x 0x10200f768 - 0x10200f600 (long) $7 = 0x0000000000000168
以此类推,找到其他属性需要的偏移量。我之前写的blog中提到的CE(cheat engine)也是一样的。
刚入职新公司,尝试一个新职业:安全开发岗,今年主要开发项目:数据隐写(Steganography),数据脱敏技术,移动端安全SDK,终端检测响应技术(EDR),有经验的朋友可以一起探讨一下。感谢🙏
实在是没时间了。以后继续完善 auto aim 自动瞄准和glowESP 人物区域。
游戏截图: