我是靠谱客的博主 柔弱棉花糖,最近开发中收集的这篇文章主要介绍第二枚ARM汇编程序分析,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

标 题: 【原创】第二枚ARM汇编程序分析
作 者: Speeday
时 间: 2013-07-31,17:28:24
链 接: http://bbs.pediy.com/showthread.php?t=176423

前几天 发了一个ARM汇编版的CrackMe,好像还挺 受欢迎的,但是由于.o文件无法由安卓程序调用,所以只能在dos下用adb shell 执行,看上去很不直观,引起一些朋友不解。
今天 我给大家 写了一个so文件 ,这样android 程序 就可以调用它了,再加上安卓的界面,看起来就要舒服点,呵呵。
由于 本人根本没学过安卓开发,所以要写个复杂的程序还是比较困难的,而分析arm汇编的指令又不需要看安卓代码 ,因此我在sample中找了一个HelloJni程序,向里面
加了一段自己写的c代码,就这样,分析旅程就开始了。
我写这个程序旨在熟悉ARM汇编指令,所以我尽可能的让它产生各种指令,如MUL,SUB,EOR,LDR,STR等,再加入程序执行的各种流程,如顺序,if else,for循环,while循环,switch case,还有一个子程序调用。
代码:
.text:00000D4C ; ---------------------------------------------------------------------------
.text:00000D4C
.text:00000D4C
EXPORT Java_com_example_hellojni_MainActivity_stringFromJNI
.text:00000D4C Java_com_example_hellojni_MainActivity_stringFromJNI
.text:00000D4C
STMFD
SP!, {R4-R8,LR}
.text:00000D50
LDR
R3, =(aWww_mengwuji_net - 0xD64)
.text:00000D54
SUB
SP, SP, #0x80
.text:00000D58
ADD
R12, SP, #0x6C
.text:00000D5C
ADD
R3, PC, R3
; www.mengwuji.net
.text:00000D60
MOV
R5, R0
.text:00000D64
LDR
R6, =(unk_23A8 - 0xD78)
.text:00000D68
LDMIA
R3, {R0-R3}
.text:00000D6C
STMIA
R12!, {R0-R2}
.text:00000D70
ADD
R6, PC, R6
.text:00000D74
STRH
R3, [R12]
.text:00000D78
MOV
R7, R6
.text:00000D7C
ADD
LR, SP, #4
.text:00000D80
LDMIA
R7!, {R0-R3}
.text:00000D84
STMIA
LR!, {R0-R3}
.text:00000D88
LDMIA
R7!, {R0-R3}
.text:00000D8C
LDR
R4, =(__stack_chk_guard_ptr - 0xDA0)
.text:00000D90
STMIA
LR!, {R0-R3}
.text:00000D94
LDMIA
R7!, {R0-R3}
.text:00000D98
LDR
R4, [PC,R4]
.text:00000D9C
LDR
R8, [R4]
.text:00000DA0
ADD
R6, R6, #0x34
.text:00000DA4
ADD
R12, SP, #0x38
.text:00000DA8
STR
R8, [SP,#0x7C]
.text:00000DAC
STMIA
LR!, {R0-R3}
.text:00000DB0
LDMIA
R6!, {R0-R3}
.text:00000DB4
LDR
R7, [R7]
.text:00000DB8
STMIA
R12!, {R0-R3}
.text:00000DBC
LDMIA
R6!, {R0-R3}
.text:00000DC0
STMIA
R12!, {R0-R3}
.text:00000DC4
LDMIA
R6!, {R0-R3}
.text:00000DC8
STMIA
R12!, {R0-R3}
.text:00000DCC
LDR
R3, [R6]
.text:00000DD0
ADD
R0, SP, #0x6C
.text:00000DD4
STR
R7, [LR]
.text:00000DD8
STR
R3, [R12]
.text:00000DDC
BL
strlen
.text:00000DE0
CMP
R0, #0
.text:00000DE4
BLE
loc_E78
.text:00000DE8
ADD
R6, SP, #0x6C
.text:00000DEC
MOV
R12, SP
.text:00000DF0
ADD
R7, R6, R0
.text:00000DF4
MOV
R3, R6
.text:00000DF8
前面这一段,实际就是在做数据处理,把程序要用到的数据,放在各个地方,方便下面使用,这些代码就是把数据挪过去挪过来的,如果有不懂的请跳转到下面的链接,也就是我的上一篇文章中。
                   第一枚ARM汇编版CrackMe分析
                    http://bbs.pediy.com/showthread.php?...97#post1204097


代码:
for循环:
.text:00000DF8 loc_DF8
; CODE XREF: .text:00000E24j
.text:00000DF8
LDR
R1, [R12,#4]!
; 取name[i]的值
.text:00000DFC
LDRB
R2, [R3]
; R3等于变量i,作为循环基数
.text:00000E00
EOR
R2, R1, R2
; 进行异或运算
.text:00000E04
AND
R2, R2, #0xFF
; 若得到的数越界,则取低8位
.text:00000E08
SUB
R1, R2, #0x14
; name[i]减20
.text:00000E0C
TST
R1, #1
; 判断数值是否为2的倍数
.text:00000E10
STRB
R1, [R3],#1
; 将R1的值存入R3所指向的地址,完成后R3加1
.text:00000E14
SUBEQ
R2, R2, #0xA
; 是2的倍数,则减10
.text:00000E18
SUBNE
R2, R2, #0xF
; 不是2的倍数,则减15
.text:00000E1C
CMP
R3, R7
; R7是字符串长度,循环的上限
.text:00000E20
STRB
R2, [R3,#-1]
; 将R2的值,存入到[R3-1]所指向的地址
.text:00000E24
BNE
loc_DF8
; for循环条件判断
注意这几句代码的逻辑:
.text:00000E08                 SUB     R1, R2, #0x14
.text:00000E0C                 TST     R1, #1         
.text:00000E10                 STRB    R1, [R3],#1    
.text:00000E14                 SUBEQ   R2, R2, #0xA   
.text:00000E18                 SUBNE   R2, R2, #0xF   
.text:00000E1C                 CMP     R3, R7         
.text:00000E20                 STRB    R2, [R3,#-1]   

一、先让R1=R2-0x14,再检测R1的值是否为2的倍数,然后把R1的值存入到内存单元,假定内存单元为m1,
二、如果该值是2的倍数,则R2的值-10,若不为2的倍数,则-15.这里是不是感觉有点奇怪。原码中是如果是2的倍数,则加上10,如果不是2的倍数,则+5,这里为什么是减呢?
    我们继续往下看,发现R2-10,或-15后直接就存入了内存m1中,原为这里是结和上面r1-20一起算的。


调用子程序:
下面是子程序中的while循环中加一个switch case结构,本来不想写switch case结构的,因为这个太简单了,后来出于流程结构完整的考虑,还是把它写上吧。
代码:
.text:00000C74
STMFD
SP!, {R4,R5}
.text:00000C78
LDRB
R3, [R0]
; 取name[i]的值,其实 就是while循环的首次条件判断
.text:00000C7C
CMP
R3, #0
.text:00000C80
BEQ
loc_CF8
; 等于0则while循环结束
.text:00000C84
LDR
R4, =0xCCCCCCCD ; 为下面的求模运算作准备
.text:00000C88
ADD
R2, R0, #1
;为下一次取name数组的值做准备
.text:00000C8C
MOV
R12, #0xA
.text:00000C90
.text:00000C90 loc_C90
; CODE XREF: function+80j
.text:00000C90
MOV
R3, R3,LSR#2
; R3=R3>>2,对应源码中的name[i]=name[i]>>2
.text:00000C94
UMULL
R5, R1, R4, R3
; R1存放结果中的高数数据,R5存入低位数据
.text:00000C98
MOV
R1, R1,LSR#3
; R1=R1>>3
.text:00000C9C
MUL
R1, R12, R1
; R1=R12*R1
.text:00000CA0
RSB
R1, R1, R3
; 逆减法指令,R1=R3-R1
.text:00000CA4
AND
R1, R1, #0xFF
; 如果越界,则取低8位的数
这一段指令看上去不知道是要做什么,各种乘法加减法的,实际上你只要分析一个数据 ,你就知道它是拿来实现求模运算的。
拿第一个数据来比如设a=16,那么按照上面的算法有。
0xcccccccd*16=cccccccd0,高位存入R1,于是R1等于C;
下一句等价于R1=R1>>3,=>R1=R1/8=1;
然后mul r1,r12,r1=>r1=1*10=10;
rsb  r1,r1,r3=>r3-r1=16-10=6;
而16%10=6,所以这就是求模运算的步骤了。

代码:
.text:00000CA8
SUB
R1, R1, #1
; R1=R1-1
.text:00000CAC
STRB
R3, [R0]
; 将R3的值存入R0所指向的寄存器中
.text:00000CB0
CMP
R1, #8
; switch 9 cases
.text:00000CB4
ADDLS
PC, PC, R1,LSL#2 ; switch jump
.text:00000CB8
B
loc_D38
; jumptable 00000CB4 default case
.text:00000CBC ; ---------------------------------------------------------------------------
.text:00000CBC
.text:00000CBC loc_CBC
; CODE XREF: function+40j
.text:00000CBC
B
loc_D30
; jumptable 00000CB4 case 0
.text:00000CC0 ; ---------------------------------------------------------------------------
.text:00000CC0
.text:00000CC0 loc_CC0
; CODE XREF: function+40j
.text:00000CC0
B
loc_D28
; jumptable 00000CB4 case 1
.text:00000CC4 ; ---------------------------------------------------------------------------
.text:00000CC4
.text:00000CC4 loc_CC4
; CODE XREF: function+40j
.text:00000CC4
B
loc_D20
; jumptable 00000CB4 case 2
.text:00000CC8 ; ---------------------------------------------------------------------------
.text:00000CC8
.text:00000CC8 loc_CC8
; CODE XREF: function+40j
.text:00000CC8
B
loc_D18
; jumptable 00000CB4 case 3
.text:00000CCC ; ---------------------------------------------------------------------------
.text:00000CCC
.text:00000CCC loc_CCC
; CODE XREF: function+40j
.text:00000CCC
B
loc_D10
; jumptable 00000CB4 case 4
.text:00000CD0 ; ---------------------------------------------------------------------------
.text:00000CD0
.text:00000CD0 loc_CD0
; CODE XREF: function+40j
.text:00000CD0
B
loc_D08
; jumptable 00000CB4 case 5
.text:00000CD4 ; ---------------------------------------------------------------------------
.text:00000CD4
.text:00000CD4 loc_CD4
; CODE XREF: function+40j
.text:00000CD4
B
loc_D00
; jumptable 00000CB4 case 6
.text:00000CD8 ; ---------------------------------------------------------------------------
.text:00000CD8
.text:00000CD8 loc_CD8
; CODE XREF: function+40j
.text:00000CD8
B
loc_CE0
; jumptable 00000CB4 case 7
.text:00000CDC ; ---------------------------------------------------------------------------
.text:00000CDC
.text:00000CDC loc_CDC
; CODE XREF: function+40j
.text:00000CDC
B
loc_D40
; jumptable 00000CB4 case 8
.text:00000CE0 ; ---------------------------------------------------------------------------
.text:00000CE0
.text:00000CE0 loc_CE0
; CODE XREF: function+40j
.text:00000CE0
; function:loc_CD8j
.text:00000CE0
MOV
R3, #0x70
; jumptable 00000CB4 case 7
.text:00000CE4
.text:00000CE4 loc_CE4
; CODE XREF: function+90j
.text:00000CE4
; function+98j ...
.text:00000CE4
STRB
R3, [R0]
; 将得case中得到 的值放入到name数组中
.text:00000CE8
MOV
R0, R2
.text:00000CEC
LDRB
R3, [R2],#1
; 取下一个name[i]的值,继续进行一下轮循环
.text:00000CF0
CMP
R3, #0
.text:00000CF4
BNE
loc_C90
; R3=R3>>2,对应源码中的name[i]=name[i]>>2
.text:00000CF8
.text:00000CF8 loc_CF8
; CODE XREF: function+Cj
.text:00000CF8
LDMFD
SP!, {R4,R5}
.text:00000CFC
BX
LR
; while循环结束
.text:00000D00 ; ---------------------------------------------------------------------------
.text:00000D00
.text:00000D00 loc_D00
; CODE XREF: function+40j
.text:00000D00
; function:loc_CD4j
.text:00000D00
MOV
R3, #0x6E
; jumptable 00000CB4 case 6
.text:00000D04
B
loc_CE4
; 将得case中得到 的值放入到name数组中
.text:00000D08 ; ---------------------------------------------------------------------------
.text:00000D08
.text:00000D08 loc_D08
; CODE XREF: function+40j
.text:00000D08
; function:loc_CD0j
.text:00000D08
MOV
R3, #0x6C
; jumptable 00000CB4 case 5
.text:00000D0C
B
loc_CE4
; 将得case中得到 的值放入到name数组中
.text:00000D10 ; ---------------------------------------------------------------------------
.text:00000D10
.text:00000D10 loc_D10
; CODE XREF: function+40j
.text:00000D10
; function:loc_CCCj
.text:00000D10
MOV
R3, #0x6A
; jumptable 00000CB4 case 4
.text:00000D14
B
loc_CE4
; 将得case中得到 的值放入到name数组中
.text:00000D18 ; ---------------------------------------------------------------------------
.text:00000D18
.text:00000D18 loc_D18
; CODE XREF: function+40j
.text:00000D18
; function:loc_CC8j
.text:00000D18
MOV
R3, #0x68
; jumptable 00000CB4 case 3
.text:00000D1C
B
loc_CE4
; 将得case中得到 的值放入到name数组中
.text:00000D20 ; ---------------------------------------------------------------------------
.text:00000D20
.text:00000D20 loc_D20
; CODE XREF: function+40j
.text:00000D20
; function:loc_CC4j
.text:00000D20
MOV
R3, #0x66
; jumptable 00000CB4 case 2
.text:00000D24
B
loc_CE4
; 将得case中得到 的值放入到name数组中
.text:00000D28 ; ---------------------------------------------------------------------------
.text:00000D28
.text:00000D28 loc_D28
; CODE XREF: function+40j
.text:00000D28
; function:loc_CC0j
.text:00000D28
MOV
R3, #0x64
; jumptable 00000CB4 case 1
.text:00000D2C
B
loc_CE4
; 将得case中得到 的值放入到name数组中
.text:00000D30 ; ---------------------------------------------------------------------------
.text:00000D30
.text:00000D30 loc_D30
; CODE XREF: function+40j
.text:00000D30
; function:loc_CBCj
.text:00000D30
MOV
R3, #0x62
; jumptable 00000CB4 case 0
.text:00000D34
B
loc_CE4
; 将得case中得到 的值放入到name数组中
.text:00000D38 ; ---------------------------------------------------------------------------
.text:00000D38
.text:00000D38 loc_D38
; CODE XREF: function+40j
.text:00000D38
; function+44j
.text:00000D38
MOV
R3, #0x60
; jumptable 00000CB4 default case
.text:00000D3C
B
loc_CE4
; 将得case中得到 的值放入到name数组中
.text:00000D40 ; ---------------------------------------------------------------------------
.text:00000D40
.text:00000D40 loc_D40
; CODE XREF: function+40j
.text:00000D40
; function:loc_CDCj
.text:00000D40
MOV
R3, #0x72
; jumptable 00000CB4 case 8
.text:00000D44
B
loc_CE4
; 将得case中得到 的值放入到name数组中
.text:00000D44 ; End of function function
.text:00000D44

switch case 简直太啰嗦了,但是为了全面 ,还是完整的贴上来了,呵呵。
末尾:

代码:
.text:00000E34 loc_E34
; CODE XREF: .text:00000E48j
.text:00000E34
LDRB
R2, [R6]
; 取生成的数据
.text:00000E38
LDR
R1, [R3,#4]!
; 取一串数据,用于后面生成好看的字串
.text:00000E3C
EOR
R2, R1, R2
; 进行异或运算
.text:00000E40
STRB
R2, [R6],#1
; 把运算得到 的数据存入name数组中
.text:00000E44
CMP
R6, R7
; 判断循环是否结束
.text:00000E48
BNE
loc_E34
; for循环,用于遍历数组,完成异或运算
.text:00000E4C
.text:00000E4C loc_E4C
; CODE XREF: .text:00000E80j
.text:00000E4C
LDR
R3, [R5]
.text:00000E50
MOV
R0, R5
.text:00000E54
ADD
R1, SP, #0x6C
.text:00000E58
LDR
R3, [R3,#JNINativeInterface.NewStringUTF]
;jni函数
.text:00000E5C
BLX
R3
.text:00000E60
LDR
R2, [SP,#0x7C]
.text:00000E64
LDR
R3, [R4]
.text:00000E68
CMP
R2, R3
.text:00000E6C
BNE
loc_E84
.text:00000E70
ADD
SP, SP, #0x80
.text:00000E74
LDMFD
SP!, {R4-R8,PC}
.text:00000E78 ; -------------------------------------------------------------------------
再把c程序帖上来吧,方便大学学习
代码:
#include <string.h>
#include <jni.h>
void function(char name[])
{
char key[]="0123456789";
int CaseNum,i=0;
while(name[i])
{
name[i]=name[i]>>2;
CaseNum=name[i]%10;
switch (CaseNum)
{
case 0: name[i]=key[0];
break;
case 1: name[i]=key[1];
break;
case 2: name[i]=key[2];
break;
case 3: name[i]=key[3];
break;
case 4: name[i]=key[4];
break;
case 5: name[i]=key[5];
break;
case 6: name[i]=key[6];
break;
case 7: name[i]=key[7];
break;
case 8: name[i]=key[8];
break;
case 9: name[i]=key[9];
break;
default:name[i]='x';
break;
}
name[i]=name[i]<<1;
i++;
}
}
jstring
Java_com_example_hellojni_MainActivity_stringFromJNI( JNIEnv* env,
jobject thiz )
{
char name[]="www.mengwuji.net";
int hash[]={0x10,0x12,0x14,0x46,0x18,0x1a,0x1c,0x1f,0x21,0x53,0x25,0x27,0x59,0x5b,0x2d,0x2f};
int data[16]={0x13,0x15,0x15,0x48,0x7,0x15,0x2,0x9,0x5,0x1b,0x6,0x7,0x42,0x1c,0xf,0x6};
int i,length;
length=strlen(name);
for(i=0;i<length;i++)
{
name[i]^=hash[i];
name[i]-=20;
if(name[i]%2==0)
{
name[i]+=10;
}
else
name[i]+=5;
}
function(name);
for(i=0;i<length;i++)
name[i]^=data[i];
return (*env)->NewStringUTF(env, name);
}
运行结果非常简单,不要笑。

程序就分析到这里了,如果有不明白的地方,欢迎回帖交流。
另外帮朋友打个广告:www.mengwuji.net 一个不错的内核开发论坛。

转载于:https://my.oschina.net/Draymond/blog/1017595

最后

以上就是柔弱棉花糖为你收集整理的第二枚ARM汇编程序分析的全部内容,希望文章能够帮你解决第二枚ARM汇编程序分析所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(39)

评论列表共有 0 条评论

立即
投稿
返回
顶部