第二枚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);
}
运行结果非常简单,不要笑。
名称:  1.png
查看次数: 0
文件大小:  13.4 KB
程序就分析到这里了,如果有不明白的地方,欢迎回帖交流。
另外帮朋友打个广告:www.mengwuji.net 一个不错的内核开发论坛。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
反汇编Linux/Windows OS运行的32位/64位程序/动态库文件,CPU类型:ARM PowerPC MIPS X86 操作菜单选择:文件解析 Alx+P ELF文件解析 Alt+E 另有CORE文件解调用栈、文本比较等功能。V2.0.3相对上一版本,完善ARM64、X8664、PPC64反汇编、ko反汇编,完善反汇编文本文件比较、IQ数据解析,修复小BUG;V2.0.2相对上一版本,完善ARM64、X8664反汇编、ARM64位core文件调用栈,完善文本文件比较、增加高亮、查找功能,修复小BUG;V2.0.0相对上一版本,完善ARM64反汇编、ARM64位core文件调用栈,完善C++符号名字解析,支持工具运行在英文版OS;V1.26.01相对上一版本,增加ARM64反汇编、64位core文件解析;V1.26.00相对上一版本,增强EXE反汇编,增加dbx老邮件解析、二维码功能;V1.25.07相对上一版本,增加二进制反汇编、IQ数据解析功能,完善MIPS反汇编,修复小BUG;V1.25.05相对上一版本,增加内存数据按数据类型解析功能;V1.25.04相对上一版本,完善X86反汇编,修复小BUG;V1.25.02相对上一版本,COREDUMP统计、匹配目标文件等相关功能优化,修复小BUG;V1.25.00相对上一版本,相关功能支持动态库文件,查询代码支持无符号目标文件+有符号目标文件,COREDUMP统计、与问题单关联、目标文件/CORE文件/问题单同步;V1.24.02相对上一版本,针对进程主动捕捉异常的信息定制处理进一步完善COREDUMP文件解析与应用,增强软件管理;V1.24.01相对上一版本,进一步完善COREDUMP文件解析与应用,提供部分ARM Thumb指令反汇编;V1.24.00相对上一版本,进一步完善COREDUMP文件解析与应用,提供堆栈调用关系分析;V1.23.03相对上一版本,提供32位X86反汇编;V1.23.02相对上一版本,提供源代码行查询指令地址,OBJ/COREDUMP文件解析,sprintf函数参数特定检查,完善文件拖放操作,修复小BUG;V1.23.01相对上一版本,提供ELF文件指令修改,修复ARM MLS指令反汇编错误等BUG;V1.23.00相对上一版本,提供程序地址对应源代码行查询,修复MIPS调试信息错误;V1.22相对上一版本,修复MIPS小端字节序反汇编错误,网上最新版本提示;V1.21相对上一版本,菜单调整,完善64位ELF文件解析,解析调试信息;另部分增强功能的菜单操作设有密码,如有兴趣欢迎咨询。欢迎大家反馈相关软件使用过程中的问题!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值