【逆向分析】静态分析_Navtive_小计

静态分析so小计

源APK

https://github.com/eternalsakura/ctf_pwn/blob/master/android%E9%80%86%E5%90%91/mobicrackNDK.apk

jadx

[外链图片转存失败,源站可能有防盗在这里插入!链机制,建描述]议将图片上https://传(imbog.csdnimg.cnUOIFq178e04c873d54461beea41f2c2f80d31.png)http指向s://img-blog.csdnimg.cn/178e04c873d54461beea41f2c2f80d31.png)]
通过源码发现关键函数在

public native boolean testFlag(String str);

    static {
        System.loadLibrary("mobicrackNDK");
    }

所以要看native 也就是so的代码进行分析
在这里插入图片描述
可惜ida实在是难搞,所以浅尝下hopper,下载:https://www.hopperapp.com/download.html?
把so丢进去即可。
在这里插入图片描述
点左上角的转换
在这里插入图片描述
搜索testFlag
在这里插入图片描述
这一块地址有点奇怪,无法转化为c,但是肉眼可见的可读性还行。
双击后面的代码可以跳转到指定的基地址,估计就是函数
在这里插入图片描述
点上面的可以返回
在这里插入图片描述
因此照着这个思路可以看到主要的代码逻辑在
abcdefghijklmn
这个里面
在这里插入图片描述

直接看汇编

str        r0, [sp, #0xc8 + var_C0] (把r0的字数据转移到sp+200+var_C0这个地址上)
blx        strlen@PLT   ; strlen(blx是跳转到strlen函数地址)
movs       r4, #0x0 (赋值,r4现在的值是0)
cmp        r0, #0x10 (比较r0和16的大小,这里没太懂为啥是r0的长度)
beq        loc_102e(b是跳转,eq是=0的意思,就是以上面如果条件是等于则跳转)

loc_102e

adds       r6, r4, #0x0 (r6 = r4 + 0 = 0 + 0 = 0

然后线性往下走loc_1030

loc_1030:
ldr        r2, [sp, #0xc8 + var_C0](sp+200+var_C0这个地址上的数据读出来放到r2上,也就是上面的r0的数据,r0是长度为10的字符串,这里应该是r2现在是r0的首位)
add        r1, sp, #0x14(r1 = sp + 20)
ldrb       r3, [r2, r6] (将地址为r2+r6的数据读出来放到r3上,由于r6后面在+1所以r3就是r2的每一位,也就是input[i])
subs       r3, r3, r6 (r3 = r3 - r6)(那就是input[i] = input[i]-i)
strb       r3, [r6, r1] (将r3的数据转移到r6+r1的地址上,首先我们看r1是不变的,r6在递增,所以也就是input[i]-i会逐位的放到r3上)
adds       r6, #0x1 (r6 = r6 + 1)
cmp        r6, #0x8 (r6 和 8 的数据进行比较)
bne        loc_1030 (b是跳转,ne是不等于0时跳转,这里我们注意到loc_1030依旧是这个代码块逻辑,所以这是一个循环)

也就是

for (int i = 0; i < 8; i++)
{
	r3[i] = input[i] - i;
}

当跳出循环之后再线性往下走就行

ldr        r3, =0x2f3e  ; 0x113c (伪指令,相当于mov r3,0x2f3e)
movs       r4, #0x0 (这里r4 = 0 )
strb       r4, [r1, #0x8] (把r4的数据放到r1+8上面)
add        r3, pc       ; dword_3f88 (r3 = r3 + pc)
ldr        r3, [r3]     ; dword_3f88,seed (r3 = 读r3这个地址上的值)
ldr        r0, [r3]     ; argument "__s1" for method strcmp@PLT, "QflMn`fH",seed (r0 = 读r3这个地址上的值)
blx        strcmp@PLT   ; strcmp (strcmp)
cmp        r0, r4 (比较r0 = r4的值,这里注意r3是上一个循环处理过的字符串,r0是seed)
bne        loc_111e(如果不等于0 则跳转loc_111e,相等则往下线性走)

看上去是找java层的Calc

ldr        r0, [r5]
ldr        r1, =0x1756  ; 0x1140,0x1756
ldr        r3, [r0]
add        r1, pc       ; "com/example/mobicrackndk/Calc"
ldr        r3, [r3, #0x18]
blx        r3
str        r0, [sp, #0xc8 + var_C4]
cmp        r0, r4
bne        loc_1070
package com.example.mobicrackndk;
/* loaded from: classes.dex */
public class Calc {
    public static String key;

    public static void calcKey() {
        StringBuffer sb = new StringBuffer("c7^WVHZ,");
        key = sb.reverse().toString();
    }
}

找到了calcKey这个函数

loc_1070:
ldr        r0, [r5]     ; CODE XREF=abcdefghijklmn+128
ldr        r2, =0x1763  ; 0x114c,0x1763
ldr        r3, =0x1767  ; 0x1150,0x1767
ldr        r4, [r0]
movs       r1, #0xe2
lsls       r1, r1, #0x1
add        r2, pc       ; "calcKey"
ldr        r4, [r4, r1]
add        r3, pc       ; "()V"
ldr        r1, [sp, #0xc8 + var_C4]
blx        r4
subs       r2, r0, #0x0
bne        loc_109e

取calcKey这个函数的methodid,定位到key

loc_109e:
ldr        r0, [r5]     ; argument #1 for method _ZN7_JNIEnv20CallStaticVoidMethodEP7_jclassP10_jmethodIDz, CODE XREF=abcdefghijklmn+164
ldr        r1, [sp, #0xc8 + var_C4] ; argument #2 for method _ZN7_JNIEnv20CallStaticVoidMethodEP7_jclassP10_jmethodIDz
bl         _ZN7_JNIEnv20CallStaticVoidMethodEP7_jclassP10_jmethodIDz ; _JNIEnv::CallStaticVoidMethod(_jclass*, _jmethodID*, ...)
ldr        r0, [r7]
ldr        r2, =0x1747  ; 0x115c,0x1747
ldr        r3, =0x1749  ; 0x1160,0x1749
movs       r1, #0x90
lsls       r1, r1, #0x2
ldr        r4, [r0, r1]
add        r2, pc       ; "key"
add        r3, pc       ; "Ljava/lang/String;"
adds       r0, r7, #0x0
ldr        r1, [sp, #0xc8 + var_C4]
blx        r4
subs       r4, r0, #0x0
bne        loc_10ce
loc_10ce:
ldr        r2, [r7]     ; CODE XREF=abcdefghijklmn+218
movs       r3, #0x91
lsls       r3, r3, #0x2
ldr        r3, [r2, r3]
ldr        r1, [sp, #0xc8 + var_C4]
adds       r2, r4, #0x0
adds       r0, r7, #0x0
blx        r3
adds       r1, r0, #0x0
ldr        r0, [r5]
movs       r2, #0xa9
lsls       r2, r2, #0x2
ldr        r3, [r0]
add        r4, sp, #0x20
ldr        r3, [r3, r2]
movs       r2, #0x0
blx        r3
adds       r5, r0, #0x0
b          loc_1102

注意这块的位置loc_1102 -> loc_10f4 往下走又是loc_1102


             loc_10f4:
000010f4         ldr        r1, [sp, #0xc8 + var_C0]  (r1现在又是我们输入的字符串的首位)                          ; CODE XREF=abcdefghijklmn+296
000010f6         adds       r3, r4, r6 ( r3 = r4 + r6 由于r6上面到8 所以是从8 开始) 
000010f8         subs       r3, #0x8 (r3 = r3 - 8)
000010fa         ldrb       r2, [r1, r6] (r1 + r6 的值也就是input[i] 给 r2)
000010fc         subs       r2, r2, r6 (r2 = r2-r6 也就是input[i] - i)
000010fe         strb       r2, [r3] 将r2的值存到r3
00001100         adds       r6, #0x1 (r6 = r6 + 1 )

             loc_1102:
00001102         adds       r0, r5, #0x0  这里r0 = r5 +0                                       ; argument "__s" for method strlen@PLT, CODE XREF=abcdefghijklmn+270
00001104         blx        strlen@PLT                                          ; strlen
00001108         adds       r0, #0x8 (这里r0 = len(r0) + 8)
0000110a         cmp        r6, r0  
0000110c         blo        loc_10f4 (如果r6< len(r0) + 8 则跳转到loc_10f4,这里的r0应该就是上面calc函数返回的key的值)

所以这里转换出来就是

for (int i = 8; i < 16; i++)
{
	s3[i - 8] = input[i] - i;
}

所以输入
所以输入就可以变成

input_str = "QflMn`fH,ZHVW^7c"
output_str = ""
num = 0
for i in input_str:
    output_str += i + num
    num += 1

然后就是init初始话的时候对seed进行了操作
在这里插入图片描述

             loc_117e:
0000117e         ldrb       r3, [r4, r7]                (seed从第0位开始)                        ; CODE XREF=__init_my+36
00001180         subs       r3, #0x3 (绕r3 = r3 -3 = seed[i] - 3)
00001182         strb       r3, [r6, r7] 把r3存起来
00001184         adds       r7, #0x1 (+1递增)

             loc_1186:
00001186         ldr        r4, [r5]        (r4就是seed)                                    ; CODE XREF=__init_my+16
00001188         adds       r0, r4, #0x0                                        ; argument "__s" for method strlen@PLT
0000118a         blx        strlen@PLT                                          ; strlen
0000118e         cmp        r7, r0 ( r7从0开始)
00001190         blo        loc_117e

seed先做一层-3处理,所以前8位再-3即可,然后适配下python脚本

input_str = "QflMn`fH,ZHVW^7c"
output_str = ""
num = 0
for i in input_str:
    if num < 8:
        output_str += chr(ord(i) + num - 3)
    else:
        output_str += chr(ord(i) + num)
    num += 1

print(output_str)

后话

静态分析native原生程序,初步了解汇编,后续还需要多读代码。印象比较深刻的有如下:

  • ldr是读
  • strb是存
  • mov是赋值
  • 循环大概是什么样子

参考链接

https://ctf-wiki.org/android/basic_reverse/static/so-example/
https://github.com/wnagzihxa1n/CTF-Mobile-Tutorial/blob/master/2015%E6%B5%B7%E5%B3%A1%E4%B8%A4%E5%B2%B8CTF/%E4%B8%80%E4%B8%AAAPK%EF%BC%8C%E9%80%86%E5%90%91%E8%AF%95%E8%AF%95%E5%90%A7ndk/WriteUp.md

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值