arm opcode hook
/**************************************
/* 作者:半斤八兩
/* 博客:http://cnblogs.com/bjblcracked
/* 日期:2013-09-05 11:11
/**************************************
只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
因工作需要,最近一直在研究arm.
看到论坛也有不少arm的破解文章,于是自己也写了个"CM",把玩一下.
这里就不讲破解了,重点讲ARM HOOK.
所需平台1:ubuntu x86 (build arm)
所需平台2:win7 x86 (debug arm)
所需平台3:android手机一部(root)
所需工具1:ida(analysis)
所需工具2:pscp(upload,download file)
所需工具3:putty(connect ubuntu)
所需工具4:gcc(build arm)
首先用标准C写个简单的cm.
代碼:
1 #include <stdio.h> 2 3 int IsAdd(int* pNumOne, int* pNumTwo) 4 { 5 return *pNumOne + *pNumTwo; 6 } 7 8 int main() 9 { 10 int nNumOne = 0; 11 int nNumTwo = 0; 12 int nNumResult = 0; 13 14 printf("hi arm code.\r\n"); 15 16 printf("Please Input a Name:"); 17 scanf("%d", &nNumOne); 18 19 printf("\r\n"); 20 21 printf("Please Input a Password:"); 22 scanf("%d", &nNumTwo); 23 24 printf("\r\n"); 25 26 nNumResult = IsAdd(&nNumOne, &nNumTwo); 27 28 printf("%d + %d = %d\r\n", nNumOne, nNumTwo, nNumResult); 29 30 if(nNumResult != 2013) 31 { 32 printf("error\r\n"); 33 } 34 else 35 { 36 printf("success\r\n"); 37 } 38 39 return 1; 40 }
测试代码,写的不严谨.
1). 连接ubuntu.
login as: root
root@192.168.83.150's password:
Welcome to Ubuntu 12.04.2 LTS (GNU/Linux 3.5.0-23-generic x86_64)
* Documentation: https://help.ubuntu.com/
258 packages can be updated.
89 updates are security updates.
Last login: Thu Aug 29 11:05:46 2013 from john-pc.local
root@i-G31MXP-K-T1:~# whoami
root
root@i-G31MXP-K-T1:~#
用putty.exe连接上ubuntu了,我们再把我们的源码上传上来.
2). upload cm src.
D:\Me\Company>pscp.exe -l root -pw password D:\Me\Company\armhook.c root@192.168.83.150:/root/zs/
armhook.c | 0 kB | 0.6 kB/s | ETA: 00:00:00 | 100%
D:\Me\Company>
这里我们用pscp.exe上传源码.
3). build arm.
root@i-G31MXP-K-T1:~/zs# arm-none-linux-gnueabi-gcc -static armhook.c -o armhook
root@i-G31MXP-K-T1:~/zs# ls -l
total 640
-rwxr-xr-x 1 root root 649852 Aug 29 16:16 armhook
-rw-r--r-- 1 root root 623 Aug 29 16:11 armhook.c
root@i-G31MXP-K-T1:~/zs#
用gcc编译arm.这里一定要静态编译,要不然在你的android手机上是运行不了的.
4). 下载bin到pc端
D:\Me\Company>pscp.exe -l root -pw password root@192.168.83.150:/root/zs/armhook D:\Me\Company
armhook | 634 kB | 634.6 kB/s | ETA: 00:00:00 | 100%
再用pscp.exe下载回来.
bin下载到PC上时,我们就可以用IDA调试了,我们先发到手机里面,运行一下,看看效果.
5). bin发送到手机端.
C:\Users\john\Desktop\Tools>adb push d:/me/company/armhook /data/local/tmp/
2173 KB/s (649852 bytes in 0.292s)
C:\Users\john\Desktop\Tools>adb shell
shell@android:/ $ su
su
shell@android:/ # pwd
pwd
/
shell@android:/ # cd data/local/tmp
cd data/local/tmp
shell@android:/data/local/tmp # ls
ls
armhook
shell@android:/data/local/tmp # ./armhook
./armhook
sh: ./armhook: can't execute: Permission denied
126|shell@android:/data/local/tmp # chmod 777 armhook
chmod 777 armhook
shell@android:/data/local/tmp # ./armhook
./armhook
hi arm code.
Please Input a Name:2000
2000
Please Input a Password:12
12
2000 + 12 = 2012
error
1|shell@android:/data/local/tmp # ./armhook
./armhook
hi arm code.
Please Input a Name:2000
2000
Please Input a Password:13
13
2000 + 13 = 2013
success
1|shell@android:/data/local/tmp #
6). 静态调试分析.
手机上测试完了,下面我们就用IDA来看看程序.
代碼:
1 .text:00008204 ; =============== S U B R O U T I N E ======================================= 2 .text:00008204 ; Attributes: noreturn bp-based frame 3 .text:00008204 EXPORT main 4 .text:00008204 main ; DATA XREF: _start+20o 5 .text:00008204 ; .text:off_8154o 6 .text:00008204 var_10 = -0x10 7 .text:00008204 var_C = -0xC 8 .text:00008204 var_8 = -8 9 .text:00008204 00 48 2D E9 STMFD SP!, {R11,LR} ; Store Block to Memory 10 .text:00008208 04 B0 8D E2 ADD R11, SP, #4 ; Rd = Op1 + Op2 11 .text:0000820C 10 D0 4D E2 SUB SP, SP, #0x10 ; Rd = Op1 - Op2 12 .text:00008210 00 30 A0 E3 MOV R3, #0 ; Rd = Op2 13 .text:00008214 0C 30 0B E5 STR R3, [R11,#var_C] ; Store to Memory 14 .text:00008218 00 30 A0 E3 MOV R3, #0 ; Rd = Op2 15 .text:0000821C 10 30 0B E5 STR R3, [R11,#var_10] ; Store to Memory 16 .text:00008220 00 30 A0 E3 MOV R3, #0 ; Rd = Op2 17 .text:00008224 08 30 0B E5 STR R3, [R11,#var_8] ; Store to Memory 18 .text:00008228 BC 00 9F E5 LDR R0, =aHiArmCode_ ; "hi arm code.\r" 19 .text:0000822C 19 0B 00 EB BL puts ; Branch with Link 20 .text:00008230 B8 30 9F E5 LDR R3, =aPleaseInputANa ; "Please Input a Name:" 21 .text:00008234 03 00 A0 E1 MOV R0, R3 ; Rd = Op2 22 .text:00008238 80 0A 00 EB BL printf ; Branch with Link 23 .text:0000823C B0 20 9F E5 LDR R2, =aD ; "%d" 24 .text:00008240 0C 30 4B E2 SUB R3, R11, #-var_C ; Rd = Op1 - Op2 25 .text:00008244 02 00 A0 E1 MOV R0, R2 ; Rd = Op2 26 .text:00008248 03 10 A0 E1 MOV R1, R3 ; Rd = Op2 27 .text:0000824C 8A 0A 00 EB BL __isoc99_scanf ; Branch with Link 28 .text:00008250 A0 00 9F E5 LDR R0, =asc_6FE98 ; "\r" 29 .text:00008254 0F 0B 00 EB BL puts ; Branch with Link 30 .text:00008258 9C 30 9F E5 LDR R3, =aPleaseInputAPa ; "Please Input a Password:" 31 .text:0000825C 03 00 A0 E1 MOV R0, R3 ; Rd = Op2 32 .text:00008260 76 0A 00 EB BL printf ; Branch with Link 33 .text:00008264 88 20 9F E5 LDR R2, =aD ; "%d" 34 .text:00008268 10 30 4B E2 SUB R3, R11, #-var_10 ; Rd = Op1 - Op2 35 .text:0000826C 02 00 A0 E1 MOV R0, R2 ; Rd = Op2 36 .text:00008270 03 10 A0 E1 MOV R1, R3 ; Rd = Op2 37 .text:00008274 80 0A 00 EB BL __isoc99_scanf ; Branch with Link 38 .text:00008278 78 00 9F E5 LDR R0, =asc_6FE98 ; "\r" 39 .text:0000827C 05 0B 00 EB BL puts ; Branch with Link 40 .text:00008280 0C 20 4B E2 SUB R2, R11, #-var_C ; Rd = Op1 - Op2 41 .text:00008284 10 30 4B E2 SUB R3, R11, #-var_10 ; Rd = Op1 - Op2 42 .text:00008288 02 00 A0 E1 MOV R0, R2 ; Rd = Op2 43 .text:0000828C 03 10 A0 E1 MOV R1, R3 ; Rd = Op2 44 .text:00008290 CD FF FF EB BL IsAdd ; Branch with Link 45 .text:00008294 08 00 0B E5 STR R0, [R11,#var_8] ; Store to Memory 46 .text:00008298 60 10 9F E5 LDR R1, =aDDD ; "%d + %d = %d\r\n" 47 .text:0000829C 0C 20 1B E5 LDR R2, [R11,#var_C] ; Load from Memory 48 .text:000082A0 10 30 1B E5 LDR R3, [R11,#var_10] ; Load from Memory 49 .text:000082A4 01 00 A0 E1 MOV R0, R1 ; Rd = Op2 50 .text:000082A8 02 10 A0 E1 MOV R1, R2 ; Rd = Op2 51 .text:000082AC 03 20 A0 E1 MOV R2, R3 ; Rd = Op2 52 .text:000082B0 08 30 1B E5 LDR R3, [R11,#var_8] ; Load from Memory 53 .text:000082B4 61 0A 00 EB BL printf ; Branch with Link 54 .text:000082B8 08 20 1B E5 LDR R2, [R11,#var_8] ; Load from Memory 55 .text:000082BC 40 30 9F E5 LDR R3, =0x7DD ; Load from Memory 56 .text:000082C0 03 00 52 E1 CMP R2, R3 ; Set cond. codes on Op1 - Op2 57 .text:000082C4 02 00 00 0A BEQ loc_82D4 ; Branch 58 .text:000082C8 38 00 9F E5 LDR R0, =aError ; "error\r" 59 .text:000082CC F1 0A 00 EB BL puts ; Branch with Link 60 .text:000082D0 01 00 00 EA B loc_82DC ; Branch 61 .text:000082D4 loc_82D4 ; CODE XREF: main+C0j 62 .text:000082D4 30 00 9F E5 LDR R0, =aSuccess ; "success\r" 63 .text:000082D8 EE 0A 00 EB BL puts ; Branch with Link 64 .text:000082DC loc_82DC ; CODE XREF: main+CCj 65 .text:000082DC 01 30 A0 E3 MOV R3, #1 ; Rd = Op2 66 .text:000082E0 03 00 A0 E1 MOV R0, R3 ; Rd = Op2 67 .text:000082E4 04 D0 4B E2 SUB SP, R11, #4 ; Rd = Op1 - Op2 68 .text:000082E8 00 88 BD E8 LDMFD SP!, {R11,PC} ; Load Block from Memory 69 .text:000082E8 ; End of function main 70 .text:000082EC 6C FE 06 00 off_82EC DCD aHiArmCode_ ; DATA XREF: main+24r 71 .text:000082EC ; "hi arm code.\r" 72 .text:000082F0 7C FE 06 00 off_82F0 DCD aPleaseInputANa ; DATA XREF: main+2Cr 73 .text:000082F0 ; "Please Input a Name:" 74 .text:000082F4 94 FE 06 00 off_82F4 DCD aD ; DATA XREF: main+38r 75 .text:000082F4 ; main+60r 76 .text:000082F4 ; "%d" 77 .text:000082F8 98 FE 06 00 off_82F8 DCD asc_6FE98 ; DATA XREF: main+4Cr 78 .text:000082F8 ; main+74r 79 .text:000082F8 ; "\r" 80 .text:000082FC 9C FE 06 00 off_82FC DCD aPleaseInputAPa ; DATA XREF: main+54r 81 .text:000082FC ; "Please Input a Password:" 82 .text:00008300 B8 FE 06 00 off_8300 DCD aDDD ; DATA XREF: main+94r 83 .text:00008300 ; "%d + %d = %d\r\n" 84 .text:00008304 DD 07 00 00 dword_8304 DCD 0x7DD ; DATA XREF: main+B8r 85 .text:00008308 C8 FE 06 00 off_8308 DCD aError ; DATA XREF: main+C4r 86 .text:00008308 ; "error\r" 87 .text:0000830C D0 FE 06 00 off_830C DCD aSuccess ; DATA XREF: main:loc_82D4r 88 .text:0000830C ; "success\r" 89 .text:00008310 ; =============== S U B R O U T I N E =======================================
程序很简单,看反汇编代码,一眼就能定位到magic jump.
代碼:
1 .text:000082B8 ; --------------------------------------------------------------------------- 2 .text:000082B8 08 20 1B E5 LDR R2, [R11,#var_8] ; Load from Memory 3 .text:000082BC 40 30 9F E5 LDR R3, =0x7DD ; Load from Memory 4 .text:000082C0 03 00 52 E1 CMP R2, R3 ; Set cond. codes on Op1 - Op2 5 .text:000082C4 02 00 00 0A BEQ loc_82D4 ; Branch 6 .text:000082C8 38 00 9F E5 LDR R0, =aError ; "error\r" 7 .text:000082CC F1 0A 00 EB BL puts ; Branch with Link 8 .text:000082D0 01 00 00 EA B loc_82DC ; Branch 9 .text:000082D4 ; ---------------------------------------------------------------------------
我们只要把beq改成 bne就可以了.
或者直接改成 B loc_82D4 .这样都可以实现爆破.
文本重点是讲HOOK,就不多说破解过程了.
CM写的很简洁,就一个isadd函数,那么我们就来尝试HOOK IsAdd函数.
1 .text:000081CC EXPORT IsAdd 2 .text:000081CC IsAdd ; CODE XREF: main+8Cp 3 .text:000081CC 04 B0 2D E5 STR R11, [SP,#-4]! ; Store to Memory 4 .text:000081D0 00 B0 8D E2 ADD R11, SP, #0 ; Rd = Op1 + Op2 5 .text:000081D4 0C D0 4D E2 SUB SP, SP, #0xC ; Rd = Op1 - Op2 6 .text:000081D8 08 00 0B E5 STR R0, [R11,#-8] ; Store to Memory 7 .text:000081DC 0C 10 0B E5 STR R1, [R11,#-0xC] ; Store to Memory 8 .text:000081E0 08 30 1B E5 LDR R3, [R11,#-8] ; Load from Memory 9 .text:000081E4 00 20 93 E5 LDR R2, [R3] ; Load from Memory 10 .text:000081E8 0C 30 1B E5 LDR R3, [R11,#-0xC] ; Load from Memory 11 .text:000081EC 00 30 93 E5 LDR R3, [R3] ; Load from Memory 12 .text:000081F0 03 30 82 E0 ADD R3, R2, R3 ; Rd = Op1 + Op2 13 .text:000081F4 03 00 A0 E1 MOV R0, R3 ; Rd = Op2 14 .text:000081F8 00 D0 8B E2 MOV SP, R11 ; Rd = Op2 15 .text:000081FC 04 B0 9D E4 LDR R11, [SP],#4 ; Load from Memory 16 .text:00008200 1E FF 2F E1 BX LR ; Branch to/from Thumb mode
其HOOK思路和x86下是一样的.
不同的是更"繁琐"些,而且"jmp"计算公式也略有不同.
在arm中,没有jmp指令,而是只有bcc指令(类似jcc).
之所以说HOOK繁琐,主要是对arm指令集不了解,所以HOOK起来感觉更繁琐些,其实都一样的,甚至更简单些 :)
具体的bcc,大家可以看我博客收集的一篇文章.
传送门:
ARM Cortex M3指令集
在arm中hook我们需要用到 bl 这个转移指令 .
其效果和x86中的 call 有点类似.
下面来说说arm bcc的公式.(自己多次尝试总结的,如果有不对的地方希望大家能指点一下.)
计算opcode:
(dst - src) / 4 - 2 = opcode
计算dst:
src + (opcode + 2) * 4 = dst
不明看例:)
1 ROM:9D039D3C 108 1C 00 00 1A BNE loc_9D039DB4 ; Branch 2 (9D039DB4 - 9D039D3C) / 4 - 2 = 1c 3 9D039D3C + (1c + 2) * 4 = 9D039DB4 4 5 6 7 ROM:9D039D90 108 07 00 00 EA B loc_9D039DB4 ; Branch 8 (9D039DB4 - 9D039D90) / 4 - 2 = 7 9 9D039D90 + (7 + 2) * 4 = 9D039DB4
下面开始HOOK,我们需要先把入口代码和地址记下来.
000081CC 04 B0 2D E5 STR R11, [SP,#-4+var_s0]! ; Store to Memory
要HOOK地址:000081CC
OPCODE:04 B0 2D E5
下面我们再程序中找段空数据地址.
1 .rodata:00072320 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 2 .rodata:00072324 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 3 .rodata:00072328 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 4 .rodata:0007232C 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 5 .rodata:00072330 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 6 .rodata:00072334 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 7 .rodata:00072338 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2
我找的这个没用的数据地址.来写我们的HOOK代码.
我们套用opcode计算公式.
(dst - src) / 4 - 2 =opcode
(00072320 - 000081CC) / 4 - 2 = 0x01A853
我们计算出opcode等于0x1A852
bl 指令对应的指令是 0xeb
那么合起来就是, 53 a8 01 eb (arm很有意思,所有的指令都是4字节对齐的.)
修改,我们就直接用IDA的插件. 组合热键是 alt+e+p+b .
IDA的这个插件对ARM支持不是很友好,不能直接编写汇编代码.
因此我们只能按字节来修改了.(字节之间都要有空格,不区分大小写.)
打开后,我们在前四个字节,输入 53 a8 01 eb 然后确定就行了.
改了后如下效果.
[COLOR="red"]
1 .text:000081CC IsAdd ; CODE XREF: main+8Cp 2 .text:000081CC 53 A8 01 EB BL loc_72320 ; Branch with Link 3 .text:000081D0 00 B0 8D E2 ADD R11, SP, #0 ; Rd = Op1 + Op2 4 .text:000081D4 0C D0 4D E2 SUB SP, SP, #0xC ; Rd = Op1 - Op2 5 .text:000081D8 08 00 0B E5 STR R0, [R11,#-8] ; Store to Memory 6 .text:000081DC 0C 10 0B E5 STR R1, [R11,#-0xC] ; Store to Memory 7 .text:000081E0 08 30 1B E5 LDR R3, [R11,#-8] ; Load from Memory 8 .text:000081E4 00 20 93 E5 LDR R2, [R3] ; Load from Memory 9 .text:000081E8 0C 30 1B E5 LDR R3, [R11,#-0xC] ; Load from Memory 10 .text:000081EC 00 30 93 E5 LDR R3, [R3] ; Load from Memory 11 .text:000081F0 03 30 82 E0 ADD R3, R2, R3 ; Rd = Op1 + Op2 12 .text:000081F4 03 00 A0 E1 MOV R0, R3 ; Rd = Op2 13 .text:000081F8 00 D0 8B E2 MOV SP, R11 ; Rd = Op2 14 .text:000081FC 04 B0 9D E4 LDR R11, [SP],#4 ; Load from Memory 15 .text:00008200 1E FF 2F E1 BX LR ; Branch to/from Thumb mode
[/CODE]
注意看81cc处的指令已经被我们改了.
现在我们要到 loc_72310 这里,
我们就来打印一个"hi arm hook" 吧.
打印的话,我们要调用 puts 函数,
我们来看一下函数地址.
1 .text:0000AE98 puts ; CODE XREF: main+28p 2 .text:0000AE98 ; main+50p ... 3 .text:0000AE98 F0 47 2D E9 STMFD SP!, {R4-R10,LR} ; Alternative name is '_IO_puts' 4 .text:0000AE9C 00 90 A0 E1 MOV R9, R0 ; Rd = Op2 5 .text:0000AEA0 1E 27 00 EB BL strlen ; Branch with Link 6 .text:0000AEA4 3C 72 9F E5 LDR R7, =stdout ; Load from Memory 7 .text:0000AEA8 00 60 97 E5 LDR R6, [R7] ; Load from Memory 8 .text:0000AEAC 00 40 96 E5 LDR R4, [R6] ; Load from Memory 9 .text:0000AEB0 02 49 14 E2 ANDS R4, R4, #0x8000 ; Rd = Op1 & Op2 10 .text:0000AEB4 00 A0 A0 E1 MOV R10, R0 ; Rd = Op2 11 .text:0000AEB8 59 00 00 1A BNE loc_B024 ; Branch 12 .text:0000AEBC 48 50 96 E5 LDR R5, [R6,#0x48] ; Load from Memory 13 .text:0000AEC0 B2 FD FF EB BL __aeabi_read_tp ; Branch with Link 14 .text:0000AEC4 08 30 95 E5 LDR R3, [R5,#8] ; Load from Memory 15 .text:0000AEC8 13 8D 40 E2 SUB R8, R0, #0x4C0 ; Rd = Op1 - Op2 16 .text:0000AECC 08 00 53 E1 CMP R3, R8 ; Set cond. codes on Op1 - Op2 17 .text:0000AED0 0E 00 00 0A BEQ loc_AF10 ; Branch 18 .text:0000AED4 01 10 A0 E3 MOV R1, #1 ; Rd = Op2 19 .text:0000AED8 05 20 A0 E1 MOV R2, R5 ; Rd = Op2 20 ... 21 ...
puts地址:0000AE98
函数原型:
int puts( const char *string );
就一个参数. arm的程序都有点类似delphi的_fastcall. 通过寄存器传参.
当参数超过四个后,就会通过栈来传参. 寄存器顺序是 r0 r1 r2 r3.
puts 就一个参数,我们只要把 "hi arm hook" 地址赋给 r0 即可.
传地址不能用 mov .要用类似 lea 的 ldr 指令. opcode: 0x0000e59f
前面说了arm是四字节指令, 光 ldr 就占了 2个字节 3 和 4字节.
那么第2个字节表示的是 寄存器. 第一个字节 表示字符串的偏移.
因为arm的risc指令为单字指令,所以他的寻址只能是255.
我们在刚才找的空数据地址段下面写上 "hi arm hook"
1 .rodata:00072320 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 2 .rodata:00072324 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 3 .rodata:00072328 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 4 .rodata:0007232C 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 5 .rodata:00072330 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 6 .rodata:00072334 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 7 .rodata:00072338 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 8 .rodata:0007233C 02 0A 02 02 ANDEQ R0, R2, #0x2000 ; Rd = Op1 & Op2 9 .rodata:00072340 02 02 05 02 ANDEQ R0, R5, #0x20000000 ; Rd = Op1 & Op2 10 .rodata:00072344 0E 0F 02 02 ANDEQ R0, R2, #0x38 ; Rd = Op1 & Op2 11 .rodata:00072348 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 12 .rodata:0007234C 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 13 .rodata:0007234C ; --------------------------------------------------------------------------- 14 .rodata:00072350 68 69 20 61+aHiArmHook DCB "hi arm hook",0 15 .rodata:0007235C ; --------------------------------------------------------------------------- 16 .rodata:0007235C 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 17 .rodata:00072360 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2
在x86上,我们HOOK前要保存现场,在ARM中,也同样需要保护现场.
STMFD 指令是用来保存现场的,满递减堆栈
恢复的话,我们就用
LDMFD指令.满递减堆栈
因为我对arm指令集并不熟悉,x86上也没有发现有什么比较好的指令和汇编转换工具.
所以我也不知道代码对应的opcode是多少,也没有时间一个个去试.
所以我就直接找puts函数入口处的opcode
保存现场
F0 47 2D E9 STMFD SP!, {R4-R10,LR} // 将R4-R10 LR 入栈,满递减堆栈
恢复现场
F0 87 BD E8 LDMFD SP!, {R4-R10,PC} // 将R4-R10 LR 出栈,满递减堆栈
00072320处,我们填写 F0 47 2D E9 保存现场.
保护好现场后,我们就来实现我们要打印的内容.
00072324处,我们把这个字符串装进r0.
ldr 1字节换算公式:
dst - src - 8 = opcode
套进去后:
00072350 - 00072324 - 8 = 24
24 00 9f e5
1 .rodata:00072320 F0 47 2D E9 STMFD SP!, {R4-R10,LR} ; Store Block to Memory 2 .rodata:00072324 24 00 9F E5 LDR R0, aHiArmHook ; "hi arm hook" 3 .rodata:00072328 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 4 .rodata:0007232C 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 5 .rodata:00072330 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 6 .rodata:00072334 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 7 .rodata:00072338 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 8 .rodata:0007233C 02 0A 02 02 ANDEQ R0, R2, #0x2000 ; Rd = Op1 & Op2 9 .rodata:00072340 02 02 05 02 ANDEQ R0, R5, #0x20000000 ; Rd = Op1 & Op2 10 .rodata:00072344 0E 0F 02 02 ANDEQ R0, R2, #0x38 ; Rd = Op1 & Op2 11 .rodata:00072348 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 12 .rodata:0007234C 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 13 .rodata:0007234C ; --------------------------------------------------------------------------- 14 .rodata:00072350 68 69 20 61+aHiArmHook DCB "hi arm hook",0 ; DATA XREF: .rodata:00072324r 15 .rodata:0007235C ; --------------------------------------------------------------------------- 16 .rodata:0007235C 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2
下面我们就剩跳到puts了.
再来看一下公式.
(dst - src) / 4 - 2 =opcode
puts地址:0000AE98
(0000AE98 - 00072328) / 4 - 2 = FFFF FFFF FFFE 62DA
我们只要取三字节就行了,也就是 da62fe加上bl eb
1 .rodata:00072320 loc_72320 ; CODE XREF: .text:IsAddp 2 .rodata:00072320 F0 47 2D E9 STMFD SP!, {R4-R10,LR} ; Store Block to Memory 3 .rodata:00072324 24 00 9F E5 LDR R0, aHiArmHook ; "hi arm hook" 4 .rodata:00072328 DA 62 FE EB BL puts ; Branch with Link 5 .rodata:0007232C 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 6 .rodata:00072330 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 7 .rodata:00072334 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 8 .rodata:00072338 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 9 .rodata:0007233C 02 0A 02 02 ANDEQ R0, R2, #0x2000 ; Rd = Op1 & Op2 10 .rodata:00072340 02 02 05 02 ANDEQ R0, R5, #0x20000000 ; Rd = Op1 & Op2 11 .rodata:00072344 0E 0F 02 02 ANDEQ R0, R2, #0x38 ; Rd = Op1 & Op2 12 .rodata:00072348 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 13 .rodata:0007234C 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 14 .rodata:0007234C ; --------------------------------------------------------------------------- 15 .rodata:00072350 68 69 20 61+aHiArmHook DCB "hi arm hook",0 ; DATA XREF: .rodata:00072324r 16 .rodata:0007235C ; ---------------------------------------------------------------------------
现在弄完了,别忘了恢复我们前面HOOK的四个字节.
.text:000081CC 04 B0 2D E5 STR R11, [SP,#-4+var_s0]! ; Store to Memory
直接复制 opcode 在 00072328 这个地址补丁即可.
完事后,别忘了再跳回去.
跳回去我们直接用上面说过的 ldmfd 指令.
恢复现场
F0 87 BD E8 LDMFD SP!, {R4-R10,PC} // 将R4-R10 LR 出栈,满递减堆栈
现在好像已经弄完了,但是在我实验过程中,发现还是有问题的.
问题是puts的参数,应该传一个字符串指针.
这里和x86有点不一样.所以我们应该在 0007235C 处写个地址,指向 00072350. 要不然程序弄到手机上运行是会出错的.
00072324 处的也要改一下.改成 30 00 9F E5.
改完后,如下.
1 .rodata:00072320 loc_72320 ; CODE XREF: .text:IsAddp 2 .rodata:00072320 F0 47 2D E9 STMFD SP!, {R4-R10,LR} ; Store Block to Memory 3 .rodata:00072324 30 00 9F E5 LDR R0, =aHiArmHook ; "hi arm hook" 4 .rodata:00072328 DA 62 FE EB BL puts ; Branch with Link 5 .rodata:0007232C 04 B0 2D E5 STR R11, [SP,#-4]! ; Store to Memory 6 .rodata:00072330 F0 87 BD E8 LDMFD SP!, {R4-R10,PC} ; Load Block from Memory 7 .rodata:00072334 ; --------------------------------------------------------------------------- 8 .rodata:00072334 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 9 .rodata:00072338 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 10 .rodata:0007233C 02 0A 02 02 ANDEQ R0, R2, #0x2000 ; Rd = Op1 & Op2 11 .rodata:00072340 02 02 05 02 ANDEQ R0, R5, #0x20000000 ; Rd = Op1 & Op2 12 .rodata:00072344 0E 0F 02 02 ANDEQ R0, R2, #0x38 ; Rd = Op1 & Op2 13 .rodata:00072348 02 02 02 02 ANDEQ R0, R2, #0x20000000 ; Rd = Op1 & Op2 14 .rodata:0007234C loc_7234C ; Rd = Op1 & Op2 15 .rodata:0007234C 02 02 02 02 ANDEQ R0, R2, #0x20000000 16 .rodata:0007234C ; --------------------------------------------------------------------------- 17 .rodata:00072350 68 69 20 61+aHiArmHook DCB "hi arm hook",0 ; DATA XREF: .rodata:00072324o 18 .rodata:00072350 72 6D 20 68+ ; .rodata:off_7235Co 19 .rodata:0007235C 50 23 07 00 off_7235C DCD aHiArmHook ; DATA XREF: .rodata:00072324r 20 .rodata:0007235C ; "hi arm hook"
在IDA里面改完后,其实并没有改完.因为IDA不支持直接在原文件里面修改.
那么我们可以通过WINHEX来修改.
在IDA里面,我们用组合快捷键. alt+f+p+d 导出dif文件.
然后用记事本打开dif文件, 用winhex对应着dif文件来修改即可.
This difference file has been created by IDA armhook This difference file has been created by IDA armhook 000001CC: 04 53 000001CD: B0 A8 000001CE: 2D 01 000001CF: E5 EB 0006A320: 02 F0 0006A321: 02 47 0006A322: 02 2D 0006A323: 02 E9 0006A324: 02 30 0006A325: 02 00 0006A326: 02 9F 0006A327: 02 E5 0006A328: 02 DA 0006A329: 02 62 0006A32A: 02 FE 0006A32B: 02 EB 0006A32C: 02 04 0006A32D: 02 B0 0006A32E: 02 2D 0006A32F: 02 E5 0006A330: 02 F0 0006A331: 02 87 0006A332: 02 BD 0006A333: 02 E8 0006A350: 02 68 0006A351: 02 69 0006A352: 02 20 0006A353: 02 61 0006A354: 02 72 0006A355: 02 6D 0006A356: 0C 20 0006A357: 02 68 0006A358: 02 6F 0006A359: 02 6F 0006A35A: 02 6B 0006A35B: 03 00 0006A35C: 02 50 0006A35D: 02 23 0006A35E: 02 07 0006A35F: 02 00
7). 赶紧传手机上测试.
上传手机:
C:\Users\john\Desktop\Tools>adb push D:\Me\Company\armhook3 /data/local/tmp/
1507 KB/s (649852 bytes in 0.421s)
8). 执行程序:
$ ls
ls
armhook
armhook_ok
$ chmod 711 armhook_ok
chmod 711 armhook_ok
$ ./armhook_ok
./armhook_ok
hi arm code1.
Please Input a Name:2010
2010
Please Input a Password:3
3
hi arm hook!
2010 + 3 = 13
error
$ ./armhook_ok
./armhook_ok
hi arm code1.
Please Input a Name:2
2
Please Input a Password:2
2
hi arm hook!
2 + 2 = 13
error
$
我们可以看到 "hi arm hook!" 字符串了,说明我们HOOK是很成功的.
但是我们可以看到我运行了2次,返回的值始终是13.
有兴趣的可以看看是怎么回事 这里我就不做解释了,我们的arm opcode hook就这样完成了
源码和程序下载地址:看雪学院