首页
论坛
课程
招聘
[原创]ollvm算法还原案例分享
2020-7-13 14:55 5035

[原创]ollvm算法还原案例分享

2020-7-13 14:55
5035

样本来自看雪3W班5月题
本题主要是还原so的算法函数,关键算法函数很好定位,主要还原方法是frida+ida调试+ida trace
1、找到对应产生结果的函数public native byte[] e(byte[] arg1)

public class MainActivity extends AppCompatActivity {
    static {
        System.loadLibrary("native-lib");
    }
    public native byte[] d(byte[] arg1) {
    }
    public native byte[] e(byte[] arg1) {
    }

    @Override  // androidx.appcompat.app.AppCompatActivity
    protected void onCreate(Bundle arg3) {
        super.onCreate(arg3);
        this.setContentView(0x7F09001C);  // layout:activity_main
        TextView v3 = (TextView)this.findViewById(0x7F070061);  // id:sample_text
        StringBuilder v0 = new StringBuilder();
        v0.append("pediy_imyang_");
        v0.append(RandomStringUtils.randomAlphabetic(10));
        v3.setText(ByteString.of(this.e(v0.toString().getBytes())).hex());
    }
}

2、固定入参,打印参数

function hook_java(){
    Java.perform(function () {
        //org.apache.commons.lang3.RandomStringUtils.randomAlphabetic(int): java.lang.String
        var RandomStringUtils = Java.use("org.apache.commons.lang3.RandomStringUtils");
        RandomStringUtils.randomAlphabetic.overload('int').implementation = function(arg){
            var result = this.randomAlphabetic(arg);
            // console.log("org.apache.commons.lang3.RandomStringUtils.randomAlphabetic:", result);
            result = "lXcaTALmow";
            return result;
        }

        //com.kanxue.ollvm5.MainActivity.encryt(byte[]): byte[]
        var ByteString = Java.use("com.android.okhttp.okio.ByteString");

        var MainActivity = Java.use("com.kanxue.ollvm5.MainActivity");
        MainActivity.e.implementation = function(arg){
            var result = this.e(arg);
            console.log("com.kanxue.ollvm5.MainActivity arg:", ByteString.of(arg).hex());
            console.log("com.kanxue.ollvm5.MainActivity result:", ByteString.of(result).hex());
            return result;
        }

    });
}

得到结果:

com.kanxue.ollvm5.MainActivity arg: 70656469795f696d79616e675f6c58636154414c6d6f77
com.kanxue.ollvm5.MainActivity result: 797903090001a4b8b6c89eb47f4f29b44d47c7382f851ad57618f9b820c5d55298cb5f941c8c

3、ida打开对应so,找到jbyteArray __fastcall Java_com_kanxue_ollvm5_MainActivity_e(JNIEnv *env_, __int64 a2, jbyteArray ary)
函数,hook发现sub_184EC调用三次,其中第三次的arg1为结果函数

sub_184EC(&arg0, arg1, arg2);
`

查找sub_184EC引用,找到函数sub_13CE4

__int64 __fastcall sub_13CE4(__int64 result, unsigned int a2, __int64 a3, unsigned int a4, __int64 output)

4、hook sub_184EC, 根据结果可知参数类型, 第2个参数是input,第5个参数是ouput, 即sub_184EC为关键算法函数

    //13CE4
    var addr_13CE4 = base.add(0x13CE4);
    var arg13CE4_0;
    var arg13CE4_1;
    var arg13CE4_4;
    Interceptor.attach(addr_13CE4, {
        onEnter: function (args) {
            //var r2 = this.context.r2;
            arg13CE4_0 = args[0];
            arg13CE4_1 = args[1];
            arg13CE4_4 = args[4];
            console.log("addr_13CE4 onEnter args0", hexdump(args[0])); //input
            console.log("addr_13CE4 onEnter args1", args[1]);  //inputlen
            console.log("addr_13CE4 onEnter args4", hexdump(args[4]));

        },
        onLeave: function (retval) {
            console.log("addr_13CE4 onLeave args0", hexdump(arg13CE4_0));
            console.log("addr_13CE4 onLeave args1", arg13CE4_1);
            console.log("addr_13CE4 onLeave args4", hexdump(arg13CE4_4));
            // console.log("addr_13CE4 retval", hexdump(arg1));
        }
    });

frida写一个主动调用,trace一下

function call_e() {
    //主动调用函数
    //com.kanxue.ollvm5.MainActivity.e(byte[]): byte[]
    Java.perform(function () {
        var MainActivity = Java.use("com.kanxue.ollvm5.MainActivity");

        Java.choose("com.kanxue.ollvm5.MainActivity", {
            onMatch: function (instance) {
                //pediy_imyang_lXcaTALmow
                var buffer = Java.array('byte', [0x70, 0x65, 0x64, 0x69, 0x79, 0x5f, 0x69, 0x6d, 0x79, 0x61, 0x6e, 0x67, 0x5f, 0x6c, 0x58, 0x63, 0x61, 0x54, 0x41, 0x4c, 0x6d, 0x6f, 0x77])
                var result = instance.e(buffer);
                var ByteString = Java.use("com.android.okhttp.okio.ByteString");
                console.log(ByteString.of(result).hex())
            },
            onComplete: function () {
            }
        });
    });
}

从trace的结果来看只看到input没看到output
再返回仔细看,尝试hook sub_13808试试

[AOSP on msm8996::com.kanxue.ollvm5]-> android_dlopen_ext: /data/app/com.kanxue.ollvm5-BHVsEeMGCcVFJqvmRywKWw==/lib/arm64/libnative-lib.so
addr_13CE4 onEnter args0              0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
71103c3940  70 65 64 69 79 5f 69 6d 79 61 6e 67 5f 6c 58 63  pediy_imyang_lXc
71103c3950  61 54 41 4c 6d 6f 77 00 63 74 69 76 69 74 79 00  aTALmow.ctivity.
71103c3960  60 74 22 10 71 00 00 00 a0 3a 3c 10 71 00 00 00  `t".q....:<.q...
71103c3970  d8 2e 07 05 71 00 00 00 7a 69 70 3a 00 00 00 00  ....q...zip:....   
71103c3980  40 39 3c 10 71 00 00 00 78 2f f9 1f b9 bb 45 f9  @9<.q...x/....E.
71103c3990  88 61 d2 6f 00 00 00 00 01 69 70 3a 0d 00 00 00  .a.o.....ip:....
71103c39a0  e0 38 3c 10 71 00 00 00 c2 0c ec de f4 c9 52 69  .8<.q.........Ri
71103c39b0  b0 72 20 f7 70 00 00 00 01 69 70 3a 0e 00 00 00  .r .p....ip:....
71103c39c0  e0 39 3c 10 71 00 00 00 9c 37 53 f8 65 b6 7c 4b  .9<.q....7S.e.|K
71103c39d0  e0 72 20 f7 70 00 00 00 01 69 70 3a 0f 00 00 00  .r .p....ip:....
71103c39e0  80 39 3c 10 71 00 00 00 3c 06 6b 29 07 5f ca 6f  .9<.q...<.k)._.o
71103c39f0  10 73 20 f7 70 00 00 00 01 69 70 3a 10 00 00 00  .s .p....ip:....
71103c3a00  c0 39 3c 10 71 00 00 00 db 0c 87 26 01 e5 1f 47  .9<.q......&...G
71103c3a10  40 73 20 f7 70 00 00 00 01 69 70 3a 11 00 00 00  @s .p....ip:....
71103c3a20  60 39 3c 10 71 00 00 00 93 20 5d c7 0a 4f 29 a9  `9<.q.... ]..O).
71103c3a30  78 c7 c5 6f 00 00 00 00 e0 c9 38 10 71 00 00 00  x..o......8.q...
addr_13CE4 onEnter args1 0x17
addr_13808 onEnter args0              0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
79ff4fd210  77 77 77 2e 70 65 64 69 79 2e 63 6f 6d 26 6b 61  www.pediy.com&ka
79ff4fd220  6e 78 75 65 00 00 00 00 79 79 00 00 00 00 00 00  nxue....yy......
79ff4fd230  62 61 73 69 63 5f 73 74 72 69 6e 67 00 00 00 00  basic_string....
79ff4fd240  61 6c 6c 6f 63 61 74 6f 72 3c 54 3e 3a 3a 61 6c  allocator<T>::al
addr_13808 onEnter args1 0x14
addr_13808 onLeave args2              0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
7fdcb5fe70  31 f5 f5 f5 f9 43 4d 51 a8 fb 31 b6 ef 7f f7 3c  1....CMQ..1....<
7fdcb5fe80  40 ba 21 9d 7a 00 00 00 17 00 00 00 00 00 00 00  @.!.z...........
7fdcb5fe90  46 9d 4c 18 7a 00 00 00 00 00 00 00 09 00 00 00  F.L.z...........
7fdcb5fea0  60 75 49 18 7a 00 00 00 40 9d 4c 18 17 00 00 00  `uI.z...@.L.....
7fdcb5feb0  10 d2 4f ff 79 00 00 00 14 00 00 00 00 00 00 00  ..O.y...........
addr_172D0 onEnter args0 0xb6cff93c
addr_172D0 onLeave retval 0xcff93cb6
addr_172D0 onEnter args0 0xb6ef9f85
addr_172D0 onLeave retval 0x9f85b6ef
addr_172D0 onEnter args0 0xcf506afb
addr_172D0 onLeave retval 0xfbcf506a
addr_172D0 onEnter args0 0x3ca8f563
addr_172D0 onLeave retval 0xa8f5633c
addr_172D0 onEnter args0 0x63636363
addr_172D0 onLeave retval 0x63636363
addr_172D0 onEnter args0 0x63636363
addr_172D0 onLeave retval 0x63636363
addr_13CE4 onLeave args4              0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
71102c8e70  79 79 03 09 00 01 a4 b8 b6 c8 9e b4 7f 4f 29 b4  yy...........O).
71102c8e80  4d 47 c7 38 2f 85 1a d5 76 18 f9 b8 20 c5 d5 52  MG.8/...v... ..R
71102c8e90  98 cb 5f 94 1c 8c 38 3c 55 0b 00 00 00 00 00 00  .._...8<U.......
71102c8ea0  4a 61 76 61 5f 63 6f 6d 5f 6b 61 6e 78 75 65 5f  Java_com_kanxue_
71102c8eb0  6f 6c 6c 76 6d 35 5f 4d 61 69 6e 41 63 74 69 76  ollvm5_MainActiv
71102c8ec0  69 74 79 5f 65 00 00 00 56 0b 00 00 00 00 00 00  ity_e...V.......
71102c8ed0  80 a2 2c 10 71 00 00 00 71 54 b6 27 19 57 c7 d8  ..,.q...qT.'.W..
71102c8ee0  00 00 00 00 00 00 00 00 db d0 cf 94 71 00 00 00  ............q...
71102c8ef0  0e 00 00 00 00 00 00 00 57 0b 00 00 00 00 00 00  ........W.......
71102c8f00  10 a6 2c 10 71 00 00 00 3b 29 67 2f d8 63 3f 36  ..,.q...;)g/.c?6
71102c8f10  00 00 00 00 00 00 00 00 01 d1 cf 94 71 00 00 00  ............q...
71102c8f20  13 00 00 00 00 00 00 00 b8 0b 00 00 00 00 00 00  ................
71102c8f30  00 8f 2c 10 71 00 00 00 12 6d 28 cd 75 ae c6 d4  ..,.q....m(.u...
71102c8f40  00 00 00 00 00 00 00 00 25 d1 cf 94 71 00 00 00  ........%...q...
71102c8f50  18 00 00 00 00 00 00 00 c2 0b 00 00 00 00 00 00  ................
71102c8f60  90 95 2c 10 71 00 00 00 52 af da eb a8 27 dd ed  ..,.q...R....'..
com.kanxue.ollvm5.MainActivity arg: 70656469795f696d79616e675f6c58636154414c6d6f77
com.kanxue.ollvm5.MainActivity result: 797903090001a4b8b6c89eb47f4f29b44d47c7382f851ad57618f9b820c5d55298cb5f941c8c

一步一步调试,发现第一轮最先生成的是

79 79 03 09 00 01
51 4D 43 F9 
B6 CF F9 3C 
B6 EF 9F 85 
CF 50 6A FB 
EF 20 83 29 
3C A8 F5 63 
63 63 63 63 
63 63 63 63

然后才生成结果

79 79 03 09 00 01 
a4 b8 b6 c8 
9e b4 7f 4f 
29 b4 4d 47 
c7 38 2f 85 
1a d5 76 18 
f9 b8 20 c5 
d5 52 98 cb 
5f 94 1c 8c

根据trace + 第一轮生成结果比对 还原出最终算法代码如下

static char keytb_42210[] = {
                        0x77, 0x77, 0x77, 0x2e, 
                        0x70, 0x65, 0x64, 0x69, 
                        0x79, 0x2e, 0x63, 0x6f, 
                        0x6d, 0x26, 0x6b, 0x61, 
                        0x6e, 0x78, 0x75, 0x65, 0x00
                        };

static char keytbde[] = {
                        0x31, 0xf5, 0xf5, 0xf5,
                        0xf9, 0x43, 0x4d, 0x51,
                        0xa8, 0xfb, 0x31, 0xb6,
                        0xef, 0x7f, 0xf7, 0x3c,
                        0x40, 0xba, 0x21, 0x9d,
                        0x7a, 0x00
                        };

static char byte_42228[] = {0x79, 0x79, 0x00, 0x00};

static char byte_42108[] = {
                            0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30,
                            0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82,
                            0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2,
                            0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26,
                            0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71,
                            0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96,
                            0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2,
                            0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
                            0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53,
                            0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb,
                            0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa,
                            0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f,
                            0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92,
                            0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff,
                            0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44,
                            0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
                            0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46,
                            0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32,
                            0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac,
                            0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
                            0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65,
                            0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6,
                            0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b,
                            0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
                            0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1,
                            0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e,
                            0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89,
                            0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f,
                            0xb0, 0x54, 0xbb, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00,
                            0x00, 0x00, 0x00
                            };
void sub_13808(char* tb, int tblen, char* output){
    //本函数从keytb_42210 解析出 keytbde
}

int REV(int val){
    return (((val << 24) & 0xFF000000) | ((val << 8) & 0x00FF0000) | ((val >> 8) & 0x0000FF00) | ((val >> 24) & 0x000000FF));
}

int keygen_13CE4(const char* input, unsigned int inputlen, char* tb, unsigned int tblen, char* output){

    char* o13808 = new char[0x20];
    sub_13808(tb, tblen, o13808);

    output[0] = byte_42228[0];
    //LOGD("%0x %0x",0, output[0]);
    output[1] = byte_42228[1];
    output[2] = 0x03;
    output[3] = (-inputlen ^ 0xFFFFFFF0) & -inputlen;;
    output[4] = 0;
    output[5] = 1;
    //LOGD("%0x %0x",3, output[3]);
    //LOGD("%0x %0x",4, output[4]);

    for(int i = 6; i <= 0x25; i++){
        int index = input[i - 6];
        if(i - 6 >= inputlen){
            output[i] = byte_42108[0];
            //LOGD("%0x %0x",i, output[i]);
            continue;
        }
        output[i] = byte_42108[index];

        //LOGD("%0x %0x",i, output[i]);
    }

    for(int i = 0; i < tblen; i++){
        int index = tb[i];
        tb[i] = byte_42108[index];
        //LOGD("tb %0x %0x",i, tb[i]);
    }

    for(int i = 0; i <= (0x25 - 0x6)/4; i++){
        unsigned int tmp1 = 0;
        memcpy(&tmp1, keytbde+4*(i%4), sizeof(int));
        //LOGD("tmp1 %0x", tmp1);
        unsigned int tmp2 = 0;
        memcpy(&tmp2, output + i*4 + 6, sizeof(int));
        //LOGD("tmp2 %0x", tmp2);
        tmp2 = (tmp2 >> 8*(i%4)) | (tmp2 << 32 - 8*(i%4));
        //LOGD("tmp2 %0x", tmp2);
        tmp2 = REV(tmp2);

        int outputtmp = REV(tmp1 & ~tmp2 | tmp2 & ~tmp1);
        LOGD("outputtmp %0x", outputtmp);

        memcpy(output+(6+i*4), &outputtmp, sizeof(int));
    }

    for(int i=0; i<=0x25; i++){
        LOGD("output %0x %0x", i, output[i]);
    }

    return 0;
}

void main(){
    int tblen = strlen(keytb);
    const char* input = "pediy_imyang_lXcaTALmow";
    char* output = new char[0x200];
    keygen_13CE4(input, strlen(input), keytb_42210, tblen, output);
}

挖华为终端产品漏洞赢巨额奖金! 注明看雪会员还有额外奖励!!

最后于 2020-7-20 14:55 被咸鱼炒白菜编辑 ,原因:
收藏
点赞4
打赏
分享
最新回复 (11)
雪    币: 246
活跃值: 活跃值 (324)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Youlor 活跃值 2020-7-13 15:03
2
0
沙发! 感谢分享~
雪    币: 914
活跃值: 活跃值 (533)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
咸鱼炒白菜 活跃值 2020-7-13 15:04
3
0
Youlor 沙发! 感谢分享~
脱壳的大佬
雪    币: 169
活跃值: 活跃值 (7259)
能力值: ( LV9,RANK:166 )
在线值:
发帖
回帖
粉丝
0x指纹 活跃值 3 2020-7-14 16:15
4
0
感谢分享~
雪    币: 753
活跃值: 活跃值 (1265)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
梨子 活跃值 2020-7-15 13:25
5
0
菜菜棒棒棒
雪    币: 1183
活跃值: 活跃值 (129)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
richor 活跃值 2020-7-17 11:13
6
0
大佬,有个问题请教一下,第三步的时候,查找sub_184EC引用,找到函数sub_13CE4,单纯知道sub_184EC调用了三次,怎么确定第三次的调用位置呢?
雪    币: 516
活跃值: 活跃值 (113)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
白小菜 活跃值 1 2020-7-17 14:26
7
0
菜年richor 大佬,有个问题请教一下,第三步的时候,查找sub_184EC引用,找到函数sub_13CE4,单纯知道sub_184EC调用了三次,怎么确定第三次的调用位置呢?
用frida打堆栈
console.log("Backtracer" + ' called from:\n' +
Thread.backtrace(this.context, Backtracer.ACCURATE)
    .map(DebugSymbol.fromAddress).join('\n') + '\n');
雪    币: 11
活跃值: 活跃值 (23)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zpazz 活跃值 2020-7-17 14:39
8
0
梨子 菜菜棒棒棒[em_86]
捕获梨子酱 (๑•̀ㅂ•́)
雪    币: 19
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_jgzwnuxx 活跃值 2020-7-17 14:47
9
0
感谢分享
雪    币: 1183
活跃值: 活跃值 (129)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
richor 活跃值 2020-7-17 15:19
10
0
谢谢大佬
雪    币: 133
活跃值: 活跃值 (60)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Frank888 活跃值 2020-7-18 16:41
11
0
感谢分享。实测有用
雪    币: 835
活跃值: 活跃值 (448)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
看雪高研 活跃值 2020-7-22 17:16
12
2
分析被ollvm混淆的算法思路就是找到参数被加密的过程以及结果的生成过程,frida的Thread.backtrace得到调用栈可以快速分析出参数的加密过程,再结合ida trace可以分析出参数被加密的具体算法。trace日志太大的时候,参数加密过程比较多,可以从trace日志中找返回结果的生成过程,来定位到具体算法的地址。
游客
登录 | 注册 方可回帖
返回