首页
社区
课程
招聘
[原创]Flutter App 逆向思路(二)
发表于: 2020-12-20 16:59 29202

[原创]Flutter App 逆向思路(二)

2020-12-20 16:59
29202

续上篇。
1,样本下载地址,安卓,苹果链接:https://pan.baidu.com/s/1XbpkOp3t80zn1ekmJKjAOw 提取码:ys9v
2,上篇提到了两个第三方框架,附上github 地址:
https://github.com/smallbuer/flutter_aes_ecb_pkcs5 ,加密解密。
https://github.com/wozhizhizhi/flutter_getuuid.git ,设备指纹数据
3,直接hookios 的代码:
//int64 fastcall Precompiled_FlutterAesEcbPkcs5_encryptStringasync_op_18489(int64 a1, int64 a2, int64 a3, int64 a4, int64 a5) 再IDA 里看到这个函数,好像尝试下,觉得hook ,拿到函数基地址,然后直接hook 参数,从内存读取字符串。 IDA 设置基地址: 编辑---》段--》 重新设置基地址,如图
图片描述
设置为0 ,然后找到函数的地址:
图片描述
function get_func_addr(module, offset) {

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var base_addr = Module.findBaseAddress(module);
console.log("base_addr: " + base_addr);
 
console.log(hexdump(ptr(base_addr), {
         length: 16,
         header: true,
         ansi: true
     }))
 
var func_addr = base_addr.add(offset);
if (Process.arch == 'arm')
   return func_addr.add(1);  //如果是32位地址+1
else
   return func_addr;

}

 

//int64 fastcall Precompiled_FlutterAesEcbPkcs5_encryptStringasync_op_18489(int64 a1, int64 a2, int64 a3, int64 a4, int64 a5)
//{

 

///000000000054F8D8 Precompiled_FlutterAesEcbPkcs5_encryptStringasync_op_18489 int64 a1, int64 a2, int64 a3, int64 a4, int64 a5
var func_addr = get_func_addr('App', 0x54F8D8);
console.log('func_addr: ' + func_addr);

 

console.log(hexdump(ptr(func_addr), {
length: 16,
header: true,
ansi: true
}))

 

Interceptor.attach(ptr(func_addr), {
onEnter: function(args) {

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
   console.log("onEnter");
   //var num1 = args[0];
   //console.log(num1); 
   //send(num1)
 
   ///
   print_dump(args[0],100);
   print_dump(args[1],100);
   print_dump(args[2],100);
   print_dump(args[3],100);
   print_dump(args[4],100);
   //console.log(Memory.readCString(num1));
   //Memory.readAnsiString(args[4]) or Memory.readCString(args[4])
},
onLeave: function(retval) {
 
   console.log("onLeave");
   console.log(retval)
   send(retval)
   //retval.replace(3);  //返回值替换成3
  // print_dump(retval,9999);
}

});

 

function print_dump(addr,size){
var buf = Memory.readByteArray(addr,size)
console.log("[function] send@ " + addr.toString() + " "+ "length: " + size.toString() + "\n[data]")
console.log(hexdump(buf, {
offset: 0,
length: size,
header: false,
ansi: false
}));
console.log("")
}

 

/*
00000000 03 51 00 00 00 00 00 40 00 00 00 00 00 00 00 45 .Q.....@.......E
00000010 36 46 46 41 34 32 33 39 43 46 36 34 37 31 34 33 6FFA4239CF647143
00000020 38 39 35 33 42 41 45 44 31 31 30 34 45 36 44 04 8953BAED1104E6D.

 

*/

 

var func_addr = get_func_addr('App', 0x54F8D8);, App ,就是ios app运行的程序,0x54F8D8函数基地址,然后hook 上, 输出了几个参数, 有用的好像是 6FFA4239CF6471,好像对应的是请求里边的一个数据:

 

图片描述

 

。自己写了一份flutter 代码,尝试了下,这个6Fxxx 不是签名的key。
继续翻代码,flutter_aes_ecb_pkcs5项目中的, /字符串加密(16进制)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
插入代码
继续翻代码,flutter_aes_ecb_pkcs5项目中的, /字符串加密(16进制)
+ (NSString *)encyptPKCS5:(NSString *)plainText WithKey:(NSString *)key{
 
    //把string 转NSData
    NSData* data = [plainText dataUsingEncoding:NSUTF8StringEncoding];
 
    //length
    size_t plainTextBufferSize = [data length];
 
    const void *vplainText = (const void *)[data bytes];
 
    uint8_t *bufferPtr = NULL;
    size_t bufferPtrSize = 0;
    size_t movedBytes = 0;
 
    bufferPtrSize = (plainTextBufferSize + kCCBlockSizeAES128) & ~(kCCBlockSizeAES128 - 1);
    bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
    memset((void *)bufferPtr, 0x0, bufferPtrSize);
    //解密hex加密的密钥
    char *publicKey = [FlutterAesEcbPkcs5Plugin convertHexStrToChar:key];
 
    NSLog(@"vkey->len->%d",strlen(publicKey));
 
    //配置CCCrypt
    CCCryptorStatus ccStatus = CCCrypt(kCCEncrypt,
                                       kCCAlgorithmAES128, //3DES
                                       kCCOptionECBMode|kCCOptionPKCS7Padding, //设置模式
                                       publicKey,    //key
                                       kCCKeySizeAES128,
                                       nil,     //偏移量,这里不用,设置为nil;不用的话,必须为nil,不可以为@“”
                                       vplainText,
                                       plainTextBufferSize,
                                       (void *)bufferPtr,
                                       bufferPtrSize,
                                       &movedBytes);
 
    if (ccStatus == kCCSuccess) {
        NSData *myData = [NSData dataWithBytes:(const char *)bufferPtr length:(NSUInteger)movedBytes];
 
        //16进制(你也可以换成base64等)
        NSUInteger          len = [myData length];
        char *              chars = (char *)[myData bytes];
        NSMutableString *   hexString = [[NSMutableString alloc] init];
 
        for(NSUInteger i = 0; i < len; i++ )
            [hexString appendString:[NSString stringWithFormat:@"%0.2hhx", chars[i]]];
        return hexString;
    }
 
    free(bufferPtr);
    return nil;

他是调用了iOS 原生的ccrypt 加密的,所以直接hook。
执行frida-trace -U -i "CCCrypt*" RESULTNUMS, 得到frida 自动生成的代码,稍微改动一下。
图片描述

 

//02zwncxia9i6n1lt
var addr = args[3]
var size = 18
var buf = Memory.readByteArray(addr,size)
console.log("[function] send@ " + addr.toString() + " "+ "length: " + size.toString() + "\n[data]")
console.log(hexdump(buf, {
offset: 0,
length: size,
header: false,
ansi: false
}));
因为args[3] 是key,我就打印了key 的值,最终结果是:02zwncxia9i6n1lt。
Dart 代理里边示例是32位16进制的字符串,这里是18位,继续看代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
插入代码
+ (char *)convertHexStrToChar:(NSString *)hexString {
 
    int mallocLen = [hexString length] / 2 + 1;
 
    char *myBuffer = (unsigned char *)malloc(mallocLen);
 
    memset(myBuffer,'\0',mallocLen);
 
    for (int i = 0; i < [hexString length] - 1; i += 2) {
        unsigned int anInt;
        NSString * hexCharStr = [hexString substringWithRange:NSMakeRange(i, 2)];
        NSScanner * scanner = [[NSScanner alloc] initWithString:hexCharStr];
        [scanner scanHexInt:&anInt];
        myBuffer[i / 2] = (char)anInt;
    }
    return myBuffer;
}

还是开源项目里边的,把16进制字符串压缩成18位,我写了一个反向的c#代码,转换了一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
插入代码
 
void Main()
{
  testint();   
  string input = "02zwncxia9i6n1lt";
  string ret = "";
   for(int =0 ;i < input.Length; i ++) {
       char t = input[i];
       int bar = Convert.ToInt32(t);
       ret += String.Format("{0:X}", bar);
   }
   ret.Dump();
}
 
void testint() {
    "begin".Dump();
}

最终输出:30327A776E637869613969366E316C74

 

然后按照示例,解密一下接口返回的参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
插入代码
 
var encryptText = "80ff0acb4785afa19f1496b966c79c3394dfc9f7e2d333186eb49cfda094e5c02ba7217fa6697343e090679dfbbf0d9571cfdca894251bd6faff2388c0331bf20b976624c2391d3a229418bacb383f9740cbf3d5ca095525306f3d037c1260ce37a02a5d01e103229688d649a9b14a4ee84c9126c0a6b30bd586b50008a8db23006bf3bfb0d25cc834fe2c5767ad92dff37d3666e3175f21ca29b952ba6a8c12b4ce64987daeacf95052fd05943816268c1f53cdcfaa67ce6f174f8c8c2be40c0cf2e8ab71d260ce56b22f5c182c729ba8c4639f0043f8a225fd8b7ec398e937cabda159a48b774729ecc39244144b1816f6c83c0fc5aec225c1e96aa6bd696804e9f7af266d8d6892a679272e43dfb22aa1602c1a3b586b450fe42a9b1b77863f77a043dfe7c80f65080712d0ed13651ebdbc095a7f03ea9f01b9fe54f8493f5eff105f61440ac65672adc7f68ed07d753d60b58ae27f911e7a26c75fd8fd00242f12f40a2581ad37d59f7b583b4c7a192576cab7f19768dab1ffd56e05d20fb3a87636956bb4c12661023b50b2f4b377a13bc1de0fb23b14bdf7386ed58f61fd70a18d9eecd3624bb07f7e61ab87726a6e8de276d098ad62e6c8a023c8c66310bd8905dfb5e589f9f91dc973d59697b75ce2ed6be669fc27acc04529558c3c8b3afe54632e0bcf0d5dc9a0ff8dea2055d4e86f51d238c25c8238e1c3801183971665133d6113c226172e50768ceb0a28457f3794afe55f6bb71c63743b2ae14c788432d40914f66dd04dd5a8041b1d7371a722e90050e61efd329e4099926545b58a7b1aaa803b6993f10ab4823cf37d097722067125979fb282feb315fda4d0f702456dd5b49a22c8dd30ab95bef5";
   // var key = "8f2d0ec58552424fa74cb70823f5acfa";
    // hook 出来的
    var key = "30327A776E637869613969366E316C74";
   // var key = "E6FFA4239CF6471438953BAED1104E6D";
 
    var data = "{\"username\":\"helloword\"}";
 
    //generate a 16-byte random key
    //var key = await FlutterAesEcbPkcs5.generateDesKey(128);
 
   // print(key);
    //encrypt
    var encryptText2 = await FlutterAesEcbPkcs5.encryptString(data, key);
 
    //time=2020-11-17+12%3A44%3A45&version=2.23&device=android&data=E6FFA4239CF6471438953BAED1104E6D&sign=66e29c02854094f0ad864b09cd75a025
    var test2 = "E6FFA4239CF6471438953BAED1104E6D";
 
 
    var test3 = "F4D2AD84F5FECE9425358C4BF968D5CC3F71217A8B027B2EFE2FB2747982BEB6";
    print(encryptText2);
    var decryptText  = await FlutterAesEcbPkcs5.decryptString(encryptText, key);
 
print(decryptText);

返回:
{"id":"11296165","username":"N6BFG1JY","nickname":"董璐蕊","phone":"","img":"http:\/\/cdn-img-new.houxiaoliang.com\/media\/headico\/20.enc?ext=.png&_v=20190812&time=1604160000&token=d8969542f2ed9aed7c72956f281844ce","group_id":"","group_name":"游客","sex":"0","group_start_time":"","group_end_time":"","share_num":"0","parent_name":"","nickname_updated":"","account_img":"http:\/\/139xb.site\/image.php?type=account&username=dcf636062de96017dd9d16954e9ace9c&ext=.png&v=1.0","can_play_tips":"3\/3","can_cache_tips":"0\/0","is_vip":"n","show_city":"1","balance":"0","level":"","level_img":"","address":""}

 

4,上一篇提到一个开源项目,解析libapp.so ,找不打开源项目了,付上地址。

 

https://pan.baidu.com/s/1XbpkOp3t80zn1ekmJKjAOw 提取码:ys9v
他的作用,看起来挺好的:

  • Parses 100% of the snapshot data, including memory structures.
  • Supports many architectures and the three snapshot types (old, AppJIT and AppAOT).
  • Usually zero-config: autodetects flags & settings from the snapshot.
  • Extracts the blobs from app.so or .snapshot files automatically.
  • Stores back-references, so you can navigate the graph easily.
  • Debugging output & strict mode controls.
  • Disassembles and analyzes the compiled code to find references to VM objects.

Examples of what you can do with the parsed info:

  • Extract string table of the application
  • Find usages of a certain object
  • Export metadata for Radare2
  • Deobfuscate a snapshot by matching it with a reference one
  • Generate call graph, library dependency graph, etc.
    但是他只支持2019-10-23 | stable | v1.9.1+hotfix.6 版本,我想升级成新版本,但是发现比难,好看dartsdk 的源码才可以。

更多精彩内容关注我的知识星球


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2020-12-20 17:00 被ReverseApp编辑 ,原因:
收藏
免费 1
支持
分享
最新回复 (3)
雪    币: 47147
活跃值: (20430)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
2
同一主题内容,若篇幅不是太长,建议放一个主题帖里,拆开发不利于阅读。
2020-12-20 18:28
0
雪    币: 141
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
kanxue 同一主题内容,若篇幅不是太长,建议放一个主题帖里,拆开发不利于阅读。
好的,下次注意
2020-12-20 20:13
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
大佬 可以帮忙 分析一个  flutter 的 案例吗 
2021-7-6 17:56
0
游客
登录 | 注册 方可回帖
返回
//