4

[原创]看雪CTF2017 第6题

NearJMP 2017-6-12 21:21 981

直接jeb打开apk查看流程

00000006  invoke-virtual      EditText->getText()Editable, v0    //获取输入值
0000000C  move-result-object  v0
0000000E  invoke-virtual      Object->toString()String, v0
00000014  move-result-object  v0
00000016  invoke-virtual      String->trim()String, v0
0000001C  move-result-object  v0
0000001E  new-instance        v1, StringBuilder
00000022  invoke-direct       StringBuilder-><init>()V, v1
00000028  invoke-virtual      StringBuilder->append(String)StringBuilder, v1, v0
0000002E  invoke-virtual      StringBuilder->toString()String, v1
00000034  move-result-object  v0
00000036  invoke-virtual      String->trim()String, v0
0000003C  move-result-object  v0
0000003E  invoke-static       utils->check(String)Z, v0       //调用jni中的check函数
00000044  move-result         v0

发现验证走的是jni,用ida加载apk中的so,发现so没有加壳,但是有代码混淆,jni函数不是动态注册,可以直接找到check函数地址,

习惯性的看了下字符串列表,发现有一些16进制的字符串

.rodata:0001D5CA a5229c2bd6437c1 DCB "5229C2BD6437C15E526793F96430D0595026",0
.rodata:0001D5CA                                         ; DATA XREF: .text:00003F24o
.rodata:0001D5CA                                         ; .text:off_3FA8o
.rodata:0001D5EF a13b82d68593952 DCB "13B82D685939526D",0 ; DATA XREF: .text:00003F36o
.rodata:0001D5EF                                         ; .text:off_3FACo
.rodata:0001D600 a1410ceb874a13b DCB "1410CEB874A13B500B358D",0 ; DATA XREF: .text:00003F52o
.rodata:0001D600                                         ; .text:off_3FB0o
.rodata:0001D617 aD79d76c575ac5d DCB "D79D76C575AC5DAFC8B835",0 ; DATA XREF: .text:00003F5Co
.rodata:0001D617                                         ; .text:off_3FB4o
.rodata:0001D62E a71897fab1c51cc DCB "71897FAB1C51CCD475927D964F",0
.rodata:0001D62E                                         ; DATA XREF: .text:00003F74o
.rodata:0001D62E                                         ; .text:off_3FB8o
.rodata:0001D649 a304b53eaf18422 DCB "304B53EAF184220D345051D7A2",0
.rodata:0001D649                                         ; DATA XREF: .text:00003F7Eo
.rodata:0001D649                                         ; .text:off_3FBCo
.rodata:0001D664 a4b1d178c542ef2 DCB "4B1D178C542EF29A1042118047",0
.rodata:0001D664                                         ; DATA XREF: .text:00003FFEo
.rodata:0001D664                                         ; .text:off_4070o
.rodata:0001D67F a221dd6112a3d27 DCB "221DD6112A3D27F7",0 ; DATA XREF: .text:00004008o
.rodata:0001D67F                                         ; .text:off_4074o
.rodata:0001D690 a973c7eaa8c8b94 DCB "973C7EAA8C8B94DD9D390AA2FD",0
.rodata:0001D690                                         ; DATA XREF: .text:0000401Eo
.rodata:0001D690                                         ; .text:off_4078o
.rodata:0001D6AB a12fa6fdf29f96c DCB "12FA6FDF29F96CD212E77CC039",0
.rodata:0001D6AB                                         ; DATA XREF: .text:0000420Co
.rodata:0001D6AB                                         ; .text:off_42B8o
.rodata:0001D6C6 a6c600dafa9fe35 DCB "6C600DAFA9FE35C66C7D1EB0B9",0
.rodata:0001D6C6                                         ; DATA XREF: .text:000042FCo
.rodata:0001D6C6                                         ; .text:off_43D0o
.rodata:0001D6E1 a5ddf101b201582 DCB "5DDF101B20158266",0 ; DATA XREF: sub_44BC+7Eo
.rodata:0001D6E1                                         ; .text:off_4578o
.rodata:0001D6F2 a93581a05791938 DCB "93581A05791938828C421C",0 ; DATA XREF: sub_2652+26o
.rodata:0001D6F2                                         ; .text:off_27C4o ...
.rodata:0001D709 a13db1940305726 DCB "13DB194030572644",0

根据交叉引用到调用处,发现正是这些16进制串的解密函数,分析之后编写python解密脚本如下

def decrypt(ary, key):
    str = ''
    n = 0
    for i in range(0, len(ary)):
        if n == 8:
            n = 0
        str += chr(ary[i] ^ key[n])
        n += 1
    return str
if __name__ == '__main__':
    ary0 = [0x52, 0x29, 0xC2, 0xBD, 0x64, 0x37, 0xc1, 0x5e, 0x52, 
            0x67, 0x93, 0xf9, 0x64, 0x30, 0xd0, 0x59, 0x50, 0x26]
    key0 = [0x31, 0x48, 0xB6, 0x9D, 0x4B, 0x47, 0xB3, 0x31]
    
    ary1 = [0x13, 0xB8, 0x2D, 0x68, 0x59, 0x39, 0x52, 0x6D]
    key1 = [0x61, 0xB8, 0x2D, 0x68, 0x59, 0x39, 0x52, 0x6D]
    
    ary2 = [0x14, 0x10, 0xCE, 0xB8, 0x74, 0xA1, 0x3B, 0x50, 0x0B, 0x35, 0x8D]
    key2 = [0x67, 0x69, 0xBD, 0xE7, 0x11, 0xD1, 0x54, 0x3C]
    
    ary3 = [0xD7, 0x9D, 0x76, 0xC5, 0x75, 0xAC, 0x5D, 0xAF, 0xC8, 0xB8, 0x35]
    key3 = [0xA4, 0xE4, 0x05, 0x9A, 0x10, 0xDC, 0x32, 0xC3]
    
    ary4 = [0x71, 0x89, 0x7F, 0xAB, 0x1C, 0x51, 0xCC, 0xD4, 0x75, 0x92, 0x7D, 0x96, 0x4F]
    key4 = [0x01, 0xFD, 0x0D, 0xCA, 0x7F, 0x34, 0x93, 0xA7]
    
    ary5 = [0x30, 0x4B, 0x53, 0xEA, 0xF1, 0x84, 0x22, 0x0D, 0x34, 0x50, 0x51, 0xD7, 0xA2]
    key5 = [0x40, 0x3F, 0x21, 0x8B, 0x92, 0xE1, 0x7D, 0x7E]
    
    ary6 = [0x4B, 0x1D, 0x17, 0x8C, 0x54, 0x2E, 0xF2, 0x9A, 0x10, 0x42, 0x11, 0x80, 0x47]
    key6 = [0x64, 0x6D, 0x65, 0xE3, 0x37, 0x01, 0x9C, 0xFF]
    
    ary7 = [0x22, 0x1D, 0xD6, 0x11, 0x2A, 0x3D, 0x27, 0xF7]
    key7 = [0x50, 0x1D, 0xD6, 0x11, 0x2A, 0x3D, 0x27, 0xF7]
    
    ary8 = [0x97, 0x3C, 0x7E, 0xAA, 0x8C, 0x8B, 0x94, 0xDD, 0x9D, 0x39, 0x0A, 0xA2, 0xFD]
    key8 = [0xA7, 0x0C, 0x4E, 0x9A, 0xBC, 0xBB, 0xA4, 0xED]
    
    ary9 = [0x12, 0xFA, 0x6F, 0xDF, 0x29, 0xF9, 0x6C, 0xD2, 0x12, 0xE7, 0x7C, 0xC0, 0x39]
    key9 = [0x3D, 0x8A, 0x1D, 0xB0, 0x4A, 0xD6, 0x49, 0xB6]
    
    ary10 = [0x6C, 0x60, 0x0D, 0xAF, 0xA9, 0xFE, 0x35, 0xC6, 0x6C, 0x7D, 0x1E, 0xB0, 0xB9]
    key10 = [0x43, 0x10, 0x7F, 0xC0, 0xCA, 0xD1, 0x10, 0xA2]
    
    ary11 = [0x5D, 0xDF, 0x10, 0x1B, 0x20, 0x15, 0x82, 0x66]
    key11 = [0x2A, 0xBE, 0x79, 0x6F, 0x50, 0x7C, 0xE6, 0x66]
    
    ary12 = [0x93, 0x58, 0x1A, 0x05, 0x79, 0x19, 0x38, 0x82, 0x8C, 0x42, 0x1C]
    key12 = [0xC3, 0x0C, 0x48, 0x44, 0x3A, 0x5C, 0x67, 0xC1]
    
    ary13 = [0x13, 0xDB, 0x19, 0x40, 0x30, 0x57, 0x26, 0x44]
    key13 = [0x61, 0xB8, 0x2D, 0x68, 0x59, 0x39, 0x52, 0x6D]
    
    print 'str0:%s' % decrypt(ary0, key0)
    print 'str1:%s' % decrypt(ary1, key1)
    print 'str2:%s' % decrypt(ary2, key2)
    print 'str3:%s' % decrypt(ary3, key3)
    print 'str4:%s' % decrypt(ary4, key4)
    print 'str5:%s' % decrypt(ary5, key5)    
    print 'str6:%s' % decrypt(ary6, key6)
    print 'str7:%s' % decrypt(ary7, key7)
    print 'str8:%s' % decrypt(ary8, key8)
    print 'str9:%s' % decrypt(ary9, key9)
    print 'str10:%s' % decrypt(ary10, key10)
    print 'str11:%s' % decrypt(ary11, key11)
    print 'str12:%s' % decrypt(ary12, key12)
    print 'str13:%s' % decrypt(ary13, key13)

运行结果:

str0:cat /proc/%d/wchan
str1:r
str2:sys_epoll\0
str3:sys_epoll\0
str4:ptrace_stop\0
str5:ptrace_stop\0
str6:/proc/net/tcp
str7:r
str8:00000000:5D8A
str9:/proc/%d/maps
str10:/proc/%d/maps
str11:waitpid
str12:PTRACE_CONT
str13:rc4(int)

看来都是些反调试串,rc4(int)可能是用的算法


回到check, 静态跟流程看,发现一开始有个6的判断,大于6进入到一个死循环,猜测为验证的次数

.text:00002850                 CMP             R0, #6     //判断是否已经验证6次
.text:00002852                 BLT             loc_2874
.text:00002854                 B               sub_286C
.text:0000286C sub_286C                                ; CODE XREF: check(_JNIEnv *,_jclass *,_jstring *)+40j
.text:0000286C                                         ; sub_286C+4p
.text:0000286C                 PUSH.W          {R4-R10,LR}
.text:00002870                 BL              sub_286C
.text:00002874
.text:00002874 loc_2874                                ; CODE XREF: check(_JNIEnv *,_jclass *,_jstring *)+3Ej
.text:00002874                 LDR.W           R0, =(aAbcdefghijklmn+0x22) ; "ijklmnopqrstuvwxyz0123456789+/="
.text:00002878                 PUSH.W          {R4-R10,LR}
.text:0000287C                 POP.W           {R4-R10,LR}
.text:00002880                 B               sub_28AA

继续跟流程,发现混淆的模式很固定,跳转时使用固定模式的乱跳,进入函数后对指令进行垃圾代码填充,了解了混淆模式后可以写ida脚本来去混淆,我是直接带着混淆看了

程序会把两个字符串给局部变量,分别是Jyu3CJlVDSGQ 和 Pjpeyjk6mmH=

.text:000028F2                 MOVS            R0, #'J'
.text:000028F4                 MOVS            R1, #'y'
.text:0000295C                 STRH.W          R0, [SP,#0x22]
.text:000029C6                 STRH.W          R1, [SP,#0x24]
.text:000029CA                 MOVS            R1, #'u'
.text:00002A32                 STRH.W          R1, [SP,#0x26]
.text:00002A36                 MOVS            R1, #'3'
.text:00002A9E                 STRH.W          R1, [SP,#0x28]
.text:00002AA2                 MOVS            R1, #'C'
.text:00002B0A                 STRH.W          R1, [SP,#0x2A]
.text:00002B74                 MOVS            R1, #0
.text:00002B76                 STRH.W          R0, [SP,#0x2C]
.text:00002B7A                 MOVS            R0, #'l'
.text:00002BE2                 STRH.W          R0, [SP,#0x2E]
.text:00002BE6                 MOVS            R0, #'V'
.text:00002C4E                 STRH.W          R0, [SP,#0x30]
.text:00002C52                 MOVS            R0, #'D'
.text:00002CBA                 STRH.W          R0, [SP,#0x32]
.text:00002CBE                 MOVS            R0, #'S'
.text:00002D26                 STRH.W          R0, [SP,#0x34]
.text:00002D2A                 MOVS            R0, #'G'
.text:00002D92                 STRH.W          R0, [SP,#0x36]
.text:00002D96                 MOVS            R0, #'Q'
.text:00002DFE                 STRH.W          R0, [SP,#0x38]
;===============================================================
.text:00001A30                 MOVS            R0, #'P'
.text:00001A32                 MOVS            R1, #'p'
.text:00001A34                 STRH.W          R0, [SP,#0x22]
.text:00001A38                 MOVS            R0, #'j'
.text:00001AA0                 STRH.W          R0, [SP,#0x24]
.text:00001B0A                 MOVS            R3, #0
.text:00001B0C                 STRH.W          R1, [SP,#0x26]
.text:00001B10                 MOVS            R1, #'e'
.text:00001B78                 STRH.W          R1, [SP,#0x28]
.text:00001B7C                 MOVS            R1, #'y'
.text:00001BE4                 STRH.W          R1, [SP,#0x2A]
.text:00001C4E                 MOVW            R1, #0xFFFF
.text:00001C52                 STRH.W          R0, [SP,#0x2C]
.text:00001C56                 MOVS            R0, #'k'
.text:00001C58                 LDR.W           R12, =unk_1E216
.text:00001CC2                 MOVS            R2, #0
.text:00001CC4                 STRH.W          R0, [SP,#0x2E]
.text:00001CC8                 MOVS            R0, #'6'
.text:00001D30                 STRH.W          R0, [SP,#0x30]
.text:00001D34                 MOVS            R0, #'m'
.text:00001D9C                 STRH.W          R0, [SP,#0x32]
.text:00001E06                 ADD             R12, PC
.text:00001E08                 STRH.W          R0, [SP,#0x34]
.text:00001E0C                 MOVS            R0, #'H'
.text:00001E74                 STRH.W          R0, [SP,#0x36]
.text:00001E78                 MOVS            R0, #'='
.text:00001EE0                 STRH.W          R0, [SP,#0x38]

其他是一些计算逻辑,静态看着太费力,上动态调试,直接附加,并没有遇到反调试,再次跟流程 (以下so基址均为0xB3998000)

发现这两个字符串最终被穿插拼接成一个 JPyjup3eCyJjlkV6DmSmGHQ=,使用base64解密没有明文。继续跟

.text:B399B6B4                 LDR.W           R0, [R9]
.text:B399B6B8                 MOV             R1, R8
.text:B399B6BA                 MOVS            R2, #0
.text:B399B6BC                 MOVS            R4, #0
.text:B399B6BE                 LDR.W           R3, [R0,#0x2A4]
.text:B399B6C2                 MOV             R0, R9
.text:B399B6C4                 BLX             R3                //获取输入的字符串
...
...
...
.text:B39B1DA8                 PUSH.W          {R4-R9,LR}
.text:B39B1DAC                 ADD             R7, SP, #0xC
.text:B39B1DAE                 SUB.W           SP, SP, #0x408
.text:B39B1DB2                 SUB             SP, SP, #4
.text:B39B1DB4                 MOV             R9, R0
.text:B39B1DB6                 LDR.W           R0, =(__stack_chk_guard_ptr - 0xB39B1DBE)
.text:B39B1DBA                 ADD             R0, PC ; __stack_chk_guard_ptr
.text:B39B1DBC                 LDR             R0, [R0] ; __stack_chk_guard
.text:B39B1DBE                 LDR             R0, [R0]
.text:B39B1DC0                 STR.W           R0, [R7,#var_10]
.text:B39B1DC4                 BL              sub_B39B231C       //获取199310124853!
.text:B39B1DC8                 MOV             R8, R0
...
...
...
.text:B39B1EE4 loc_B39B1EE4                                       //循环,计算输入字符串长度
.text:B39B1EE4                 LDRB.W          R1, [R0],#1        
.text:B39B1EE8                 CMP             R1, #0
.text:B39B1EEA                 BNE             loc_B39B1EE4
.text:B39B1EEC                 MVN.W           R1, R9
.text:B39B1EF0                 ADDS            R6, R0, R1
.text:B39B1EF2                 ADDS            R4, R6, #1
...
.text:B39B1F80                 MOV             R0, R4  ; size    //根据输入字符串长度分配空间
.text:B39B1F82                 BLX             malloc
.text:B39B1F86                 MOV             R1, R4
.text:B39B1F88                 MOV             R5, R0
.text:B39B1FF0                 BLX             __aeabi_memclr
.text:B39B1FF4                 MOV             R4, SP           
.text:B39B1FF6                 MOVS            R1, #8             //rc4密钥长度
.text:B39B1FF8                 MOV             R0, R4 
.text:B39B1FFA                 MOV             R2, R8             //R8: 199310124853!
.text:B39B20C8                 BL              sub_B399D5E4       //创建一个[0-FF]的数组,并且根据19931012循环打乱

看到这里,又想到一开始的rc4(int),猜测是rc4加密后转的base64,直接用python解密,脚本如下

from Crypto.Cipher import ARC4
import base64
if __name__ == '__main__':
    key = '19931012'
    cipher = ARC4.new(key)
    print cipher.decrypt(base64.b64decode('JPyjup3eCyJjlkV6DmSmGHQ='))

解出 sn为 madebyericky94528


最新回复 (0)
返回