首页
论坛
课程
招聘
[原创]ollvm算法还原案例分享
2020-11-4 11:29 5670

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

2020-11-4 11:29
5670

看雪8月ollvm题,考察ollvm算法还原能力
1、找到对应产生结果的函数MainActivity中的public native byte[] e(byte[] arg1)

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
package com.kanxue.ollvm8;
 
import android.os.Bundle;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import okio.ByteString;
import org.apache.commons.lang3.RandomStringUtils;
 
public class MainActivity extends AppCompatActivity {
    static {
        System.loadLibrary("xxxxdun");
    }
 
    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(RandomStringUtils.randomAlphabetic(10));
        v0.append("_pediy_imyang_");
        v3.setText(ByteString.of(this.e(v0.toString().getBytes())).hex());
    }
}

2、frida固定入参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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 = "elDIkbaKit";
            return result;
        }
 
        //com.kanxue.ollvm5.MainActivity.encryt(byte[]): byte[]
        var ByteString = Java.use("com.android.okhttp.okio.ByteString");
 
        var MainActivity = Java.use("com.kanxue.ollvm8.MainActivity");
        MainActivity.e.implementation = function(arg){
            var result = this.e(arg);
            console.log("com.kanxue.ollvm8.MainActivity arg:", ByteString.of(arg).hex());
            console.log("com.kanxue.ollvm8.MainActivity result:", ByteString.of(result).hex());
            return result;
        }
 
    });
}

3、ida打开libxxxxdun.so找到对应函数,本层无混淆

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
int __fastcall Java_com_kanxue_ollvm8_MainActivity_e(JNIEnv *a1, int a2, int a3)
{
  int v5; // r6
  int v6; // r8
  int v7; // r0
  int v8; // r10
  int v9; // r6
  int v10; // r0
  _DWORD v12[3]; // [sp+4h] [bp-44h] BYREF
  char v13[12]; // [sp+10h] [bp-38h] BYREF
  char v14[12]; // [sp+1Ch] [bp-2Ch] BYREF
 
  v5 = ((int (__fastcall *)(JNIEnv *, int))(*a1)->GetArrayLength)(a1, a3);
  v6 = ((int (__fastcall *)(JNIEnv *, int, _DWORD))(*a1)->GetByteArrayElements)(a1, a3, 0);
  sub_ED80((int)v14, v6, v5);
  sub_EDA4(v12, (int)v14);
  sub_B940(v13, v12);
  sub_BE34((int)v12);
  v7 = sub_BA18(v13);
  v8 = sub_F060(a1, v7);
  v9 = sub_BA18(v13);
  v10 = sub_BB44(v13);
  ((void (__fastcall *)(JNIEnv *, int, _DWORD, int, int))(*a1)->SetByteArrayRegion)(a1, v8, 0, v9, v10);
  sub_F178(a1, a3, v6, 0);
  sub_BE34((int)v13);
  sub_BE34((int)v14);
  return v8;
}

根据hook结果

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
sub_0E210 onEnter:            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
cda0e034  21 00 00 00 18 00 00 00 40 e0 5f cc 58 e0 a0 cd  !.......@._.X...
cda0e044  11 18 df d1 16 00 00 00 21 00 00 00 18 00 00 00  ........!.......
cda0e054  c0 0f 94 cc b1 a1 eb ac 00 00 00 00 00 c4 fd dd  ................
cda0e064  88 e1 a0 cd 14 e1 a0 cd 44 c0 e0 eb 02 00 00 00  ........D.......
cda0e074  00 00 00 00 a8 e2 a0 cd 77 80 fd cc 44 c0 e0 eb  ........w...D...
cda0e084  00 00 00 00 02 00 00 00 b0 19 30 14 c0 a8 70 13  ..........0...p.
cda0e094  01 00 00 00 70 79 20 cc 01 00 00 00 24 fa 00 00  ....py .....$...
cda0e0a4  00 00 00 00 00 00 00 00 00 00 00 00 00 00 f0 3f  ...............?
cda0e0b4  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cda0e0c4  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cda0e0d4  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cda0e0e4  02 00 00 00 00 00 00 00 a8 e2 a0 cd 00 00 00 00  ................
cda0e0f4  88 e1 a0 cd 14 e1 a0 cd 77 c5 10 e9 00 00 00 00  ........w.......
cda0e104  b0 19 30 14 c0 a8 70 13 76 11 5e d2 00 01 00 00  ..0...p.v.^.....
cda0e114  00 00 00 00 02 00 00 00 00 00 00 00 a8 e2 a0 cd  ................
cda0e124  4e 00 00 00 48 e1 a0 cd 88 e1 a0 cd 00 00 00 00  N...H...........
sub_0E210 onLeave:            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
cc5fe040  65 6c 44 49 6b 62 61 4b 69 74 5f 70 65 64 69 79  elDIkbaKit_pediy
cc5fe050  5f 69 6d 79 61 6e 67 5f 00 69 76 69 74 79 00 00  _imyang_.ivity..
cc5fe060  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc5fe070  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc5fe080  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc5fe090  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc5fe0a0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc5fe0b0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc5fe0c0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc5fe0d0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc5fe0e0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc5fe0f0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc5fe100  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc5fe110  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc5fe120  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc5fe130  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

可发现,有一个结构体

1
2
3
4
5
struct {
    int n1;
    int nlen;
    char* buff;  //指向input/output的二进制
}

其中sub_B940(outputobj, inputobj);函数传入了入参和出参的结构体,分别打印该函数调用前和调用后出参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var output;
var sub_0B940 = base_libxxxxdun.add(0xB940 + 1);
Interceptor.attach(sub_0B940, {
    onEnter: function (args) {
        arg0 = args[0];
        arg1 = args[1];
        output = args[0];
        var input = ptr(arg1).add(8);
        //console.log("sub_0B940 onEnter:", hexdump((ptr(arg0).add(8)).readPointer()));
        //console.log("sub_0B940 onEnter:", hexdump(input.readPointer()));
    }, onLeave: function (ret) {
        var input = ptr(arg1).add(8);
        output = ptr(arg0).add(8);
        console.log("sub_0B940 onLeave:", hexdump(output.readPointer()));
        //console.log("sub_0B940 onLeave:", hexdump(input.readPointer()));
    }
});

得到的结果为算法结果,所以sub_B940为算法关键函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
sub_0B940 onLeave:            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
cc4fc0a0  75 8f 3e 3c 9c 5c e1 79 2d 3b 25 93 12 b6 a9 8a  u.><.\.y-;%.....
cc4fc0b0  40 59 ab 04 b1 7a 25 73 00 74 69 76 69 74 79 00  @Y...z%s.tivity.
cc4fc0c0  65 6c 44 49 6b 62 61 4b 69 74 5f 70 65 64 69 79  elDIkbaKit_pediy
cc4fc0d0  5f 69 6d 79 61 6e 67 5f 00 69 76 69 74 79 00 00  _imyang_.ivity..
cc4fc0e0  75 8f 3e 3c 9c 5c e1 79 2d 3b 25 93 12 b6 a9 8a  u.><.\.y-;%.....
cc4fc0f0  40 59 ab 04 b1 7a 25 73 00 74 69 76 69 74 79 00  @Y...z%s.tivity.
cc4fc100  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc4fc110  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc4fc120  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc4fc130  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc4fc140  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc4fc150  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc4fc160  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc4fc170  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc4fc180  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc4fc190  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

跟进sub_B940, 大致分析一下函数,发现sub_11094传入了input,且有一个用于传出的参数,比较像算法函数

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
int __fastcall func_B940(int outputobj, unsigned __int8 *inputobj)
{
  int len1; // r0
  int v5; // r6
  int inputbuff; // r4
  int len1_; // r0
  int v8; // r5
  int v9; // r0
  int v11; // [sp+8h] [bp-30h] BYREF
  int len2; // [sp+Ch] [bp-2Ch] BYREF
  unsigned __int8 v13[12]; // [sp+10h] [bp-28h] BYREF
  int v14; // [sp+1Ch] [bp-1Ch]
 
  sub_B9F8(v13);
  len1 = getlen_BA18(inputobj);
  sub_BA10(v13, len1);
  len2 = getlen_BA18(v13);
  v5 = getbuff_BB44(v13);
  inputbuff = getbuff_BB44(inputobj);
  len1_ = getlen_BA18(inputobj);
  sub_11094(v5, (int)&len2, inputbuff, len1_, 9);
  v8 = sub_BB54((int)v13);
  v11 = sub_BB54((int)v13);
  v9 = sub_BCB8(&v11, len2);
  sub_BE1C((_DWORD *)outputobj, v8, v9);
  sub_BE34((int)v13);
  return _stack_chk_guard - v14;
}

hook一下sub_011094

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var a0,a1,a2;
var sub_011094 = base_libxxxxdun.add(0x11094 + 1);
Interceptor.attach(sub_011094, {
    onEnter: function (args) {
        a0 = args[0];
        a1 = args[1];
        a2 = args[2];
        console.log("sub_011094 onEnter:", hexdump(args[0]));
        console.log("sub_011094 onEnter:", hexdump(args[1]));
        console.log("sub_011094 onEnter:", hexdump(args[2]));
        console.log("sub_011094 onEnter:", args[3]);
    }, onLeave: function (ret) {
        //var pLeave = ptr(ret).readPointer()
        //console.log("sub_011094 onLeave:", hexdump(ret));
        console.log("sub_011094 onLeave:", hexdump(a0));
        console.log("sub_011094 onLeave:", hexdump(a1));
        console.log("sub_011094 onLeave:", hexdump(a2));
    }
});

hook结果发现执行完毕有算法结果

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
sub_011094 onLeave:            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
cc840a00  75 8f 3e 3c 9c 5c e1 79 2d 3b 25 93 12 b6 a9 8a  u.><.\.y-;%.....
cc840a10  40 59 ab 04 b1 7a 25 73 00 74 69 76 69 74 79 00  @Y...z%s.tivity.
cc840a20  75 8f 3e 3c 9c 5c e1 79 2d 3b 25 93 12 b6 a9 8a  u.><.\.y-;%.....
cc840a30  40 59 ab 04 b1 7a 25 73 00 74 69 76 69 74 79 00  @Y...z%s.tivity.
cc840a40  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc840a50  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc840a60  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc840a70  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc840a80  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc840a90  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc840aa0  00 00 00 00 34 00 00 00 00 00 00 00 00 00 00 00  ....4...........
cc840ab0  00 00 00 00 51 00 00 00 00 00 14 42 00 00 00 00  ....Q......B....
cc840ac0  69 6e 64 69 72 65 63 74 20 72 65 66 20 74 61 62  indirect ref tab
cc840ad0  6c 65 00 00 00 00 00 00 00 00 00 00 00 00 00 00  le..............
cc840ae0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cc840af0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
sub_011094 onLeave:            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
cda10ffc  18 00 00 00 21 00 00 00 18 00 00 00 00 0a 84 cc  ....!...........
cda1100c  b1 a1 eb ac 58 79 a5 cc 90 10 a1 cd b8 91 da e9  ....Xy..........
cda1101c  4c 10 a1 cd 50 07 27 e9 18 00 00 00 78 10 a1 cd  L...P.'.....x...
cda1102c  f7 0c e5 cc 16 00 00 00 21 00 00 00 18 00 00 00  ........!.......
cda1103c  e0 09 84 cc 58 10 a1 cd 11 48 df d1 16 00 00 00  ....X....H......
cda1104c  21 00 00 00 18 00 00 00 c0 09 84 cc b1 a1 eb ac  !...............
cda1105c  00 00 00 00 00 1e fd dd 88 11 a1 cd 14 11 a1 cd  ................
cda1106c  44 c0 e0 eb 02 00 00 00 00 00 00 00 a8 12 a1 cd  D...............
cda1107c  77 00 fe cc 44 c0 e0 eb 00 00 00 00 02 00 00 00  w...D...........
cda1108c  98 21 dc 13 c0 a8 90 13 01 00 00 00 60 a9 26 cc  .!..........`.&.
cda1109c  01 00 00 00 24 fa 00 00 00 00 00 00 00 00 00 00  ....$...........
cda110ac  00 00 00 00 00 00 f0 3f 00 00 00 00 00 00 00 00  .......?........
cda110bc  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cda110cc  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
cda110dc  00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00  ................
cda110ec  a8 12 a1 cd 00 00 00 00 88 11 a1 cd 14 11 a1 cd  ................
sub_011094 onLeave:            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
cc8409e0  65 6c 44 49 6b 62 61 4b 69 74 5f 70 65 64 69 79  elDIkbaKit_pediy
cc8409f0  5f 69 6d 79 61 6e 67 5f 00 69 76 69 74 79 00 00  _imyang_.ivity..
cc840a00  75 8f 3e 3c 9c 5c e1 79 2d 3b 25 93 12 b6 a9 8a  u.><.\.y-;%.....
758f3e3c9c5ce1792d3b259312b6a98a4059ab04b17a2573

跟进sub_011094,发现混淆比较严重,trace一下试试
由trace逆出一轮中间值以及怎样算出最终结果的

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
void func(){
//最终结果
//    CC840A00  75 8F 3E 3C 9C 5C E1 79  2D 3B 25 93 12 B6 A9 8A  u.><.\...;%.....
//    CC840A10  40 59 AB 04 B1 7A 25 73  00 74 69 76 69 74 79 00  @Y...z%s.tivity.
 
    char input[0x19] = {0x65, 0x6c, 0x44, 0x49, 0x6b, 0x62, 0x61, 0x4b, 0x69, 0x74, 0x5f, 0x70, 0x65, 0x64, 0x69, 0x79, 0x5f, 0x69, 0x6d, 0x79, 0x61, 0x6e, 0x67, 0x5f, 0x00};
    char output[0x64] = {0};
 
//中间结果,猜测是由input转换而得
//    CC840A00  78 DA 4B CD 71 F1 CC 4E  4A F4 CE 2C 89 2F 48 4D  x............/HM
//    CC840A10  C9 AC 8C CF CC AD 4C CC  00 74 69 76 69 74 79 00  ɬ ....L..tivity.
    char temp[0x64] = {0x78, 0xDA, 0x4B, 0xCD, 0x71, 0xF1, 0xCC, 0x4E, 0x4A, 0xF4, 0xCE, 0x2C, 0x89, 0x2F, 0x48, 0x4D, 0xC9, 0xAC, 0x8C, 0xCF, 0xCC, 0xAD, 0x4C, 0xCC };
 
//中间结果转为最终结果的算法:
    for(int i = 2; i < strlen(temp); i++){
        int v94 = ((temp[i] & 0x64) + (~temp[i] & 0x9B)) ^ (((2 * output[i-1] + 117) & 0x64)
                                                            + (~(2 * output[i-1] + 117) & 0x9B));
        output[i] = v94;
        LOGI("v94 = : %0x\n", v94);
    }
 
    //前两个字节是定值
    output[0] = 0x75;
    output[1] = 0x8f;
}
}

追溯中间结果是怎么生成的
调试发现这个关键赋值位置的BLX R2,实际调用了sub_257F4

1
2
3
4
5
6
7
8
9
10
.text:0001CC84 loc_1CC84                               ; CODE XREF: sub_18D48+E86↑j
.text:0001CC84                 LDR             R1, [SP,#0x238+var_88]
.text:0001CC86                 LDR             R2, =(unk_79230 - 0x1CC92)
.text:0001CC88                 LDR             R0, [SP,#0x238+var_174]
.text:0001CC8A                 ADD.W           R1, R1, R1,LSL#1
.text:0001CC8E                 ADD             R2, PC  ; unk_79230
.text:0001CC90                 ADD.W           R1, R2, R1,LSL#2
.text:0001CC94                 LDR             R2, [R1,#8]
.text:0001CC96                 LDR             R1, [SP,#0x238+var_194]
.text:0001CC98                 BLX             R2      ; 调用0x257F4

跟进sub_257F4,找到sub_1ECFC,跟进sub_1ECFC,从memcpy往上追溯
根据memcpy的参数来源:

1
2
3
4
5
6
7
8
9
struct {
    char nop[28];
    obj* ptr;
}
 
struct obj {
    char nop[16];
    char* outTmp;
}

由此hook查看其中间结果

1
2
3
4
5
6
7
8
9
10
11
12
var sub_01ECFC = base_libxxxxdun.add(0x1ECFC + 1);
Interceptor.attach(sub_01ECFC, {
    onEnter: function (args) {
        arg0 = args[0];
        //console.log("sub_01ECFC onEnter:", hexdump(ptr(arg0).add(28)));
        var addTmp = (ptr(arg0).add(28)).readPointer();
        //console.log("sub_01ECFC onEnter:", hexdump(addTmp));
        var addResult = ptr(addTmp).add(16).readPointer();
        console.log("sub_01ECFC onEnter:", hexdump(addResult));
    }, onLeave: function (ret) {
    }
});

得到结果

1
2
3
4
5
6
7
8
sub_01ECFC onEnter:            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
d65df440  78 da 71 f1 cc 4e 4a f4 ce 2c 89 2f 48 4d c9 ac  x.q..NJ..,./HM..
d65df450  8c cf cc ad 4c cc 4b 8f 07 00 00 00 00 00 00 00  ....L.K.........
d65df460  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
sub_01ECFC onEnter:            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
d65df440  4b cd 71 f1 cc 4e 4a f4 ce 2c 89 2f 48 4d c9 ac  K.q..NJ..,./HM..
d65df450  8c cf cc ad 4c cc 4b 8f 07 00 00 00 00 00 00 00  ....L.K.........
d65df460  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

sub_1ECFC调用了两次,第二次调用时结果已经生成了,故而往上追溯sub_257F4
追溯参数来源按照同样的格式进行hook

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var sub_0257F4 = base_libxxxxdun.add(0x257F4 + 1);
Interceptor.attach(sub_0257F4, {
    onEnter: function (args) {
        arg0 = args[0];
        //console.log("sub_0257F4 onEnter:", hexdump(arg0));
        arg0 = arg0.readPointer();
        //console.log("sub_0257F4 onEnter:", hexdump(arg0));
        var addTmp = (ptr(arg0).add(28)).readPointer();
        var addResult = ptr(addTmp).add(16).readPointer();
        console.log("sub_0257F4 onEnter:", hexdump(addResult));
    }, onLeave: function (ret) {
        var addTmp = (ptr(arg0).add(28)).readPointer();
        var addResult = ptr(addTmp).add(16).readPointer();
        console.log("sub_0257F4 onLeave:", hexdump(addResult));
    }
});

得到的是一个初始结果

1
2
3
4
sub_0257F4 onEnter:            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
d65df440  78 da 71 f1 cc 4e 4a f4 ce 2c 89 2f 48 4d c9 ac  x.q..NJ..,./HM..
d65df450  8c cf cc ad 4c cc 4b 8f 07 00 00 00 00 00 00 00  ....L.K.........
d65df460  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

搜索sub_257F4里调用sub_1ECFC的位置,发现全部是类似这样的BB

1
2
3
4
5
6
v2 = a1;
v172 = a1;
...
sub_566B4(v2, input_, *v208 - *v215, 0);
*v215 = *v208;
sub_1ECFC(*v172);

于是尝试按照结构体格式hook sub_566B4 打印结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var sub_0566B4 = base_libxxxxdun.add(0x566B4 + 1);
Interceptor.attach(sub_0566B4, {
    onEnter: function (args) {
        arg0 = args[0];
        arg0 = arg0.readPointer();
        //console.log("sub_0566B4 onEnter:", hexdump(arg0));
        var addTmp = (ptr(arg0).add(28)).readPointer();
        var addResult = ptr(addTmp).add(16).readPointer();
        console.log("sub_0566B4 onEnter:", hexdump(addResult));
        // console.log("sub_0566B4 onEnter:", hexdump(args[1]));  //inputbuff
        // console.log("sub_0566B4 onEnter:", args[2]);
        // console.log("sub_0566B4 onEnter:", args[3]);
    }, onLeave: function (ret) {
        var addTmp = (ptr(arg0).add(28)).readPointer();
        var addResult = ptr(addTmp).add(16).readPointer();
        console.log("sub_0566B4 onLeave:", hexdump(addResult));
    }
});

得到结果

1
2
3
4
5
6
7
8
sub_0566B4 onEnter:            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
d65df440  78 da 71 f1 cc 4e 4a f4 ce 2c 89 2f 48 4d c9 ac  x.q..NJ..,./HM..
d65df450  8c cf cc ad 4c cc 4b 8f 07 00 00 00 00 00 00 00  ....L.K.........
d65df460  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
sub_0566B4 onLeave:            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
d65df440  4b cd 71 f1 cc 4e 4a f4 ce 2c 89 2f 48 4d c9 ac  K.q..NJ..,./HM..
d65df450  8c cf cc ad 4c cc 4b 8f 07 00 00 00 00 00 00 00  ....L.K.........
d65df460  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

调试该函数,得到sub_5A6DC函数,在此处赋值

1
2
3
.text:0005B2E2                 ADD             R6, R12
.text:0005B2E4                 STR             R6, [R0,#0x14]
.text:0005B2E6                 STRB            R2, [R4,R5]

trace一下sub_5A6DC, 得到算法全貌

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
int ary[] = {
 
        0x8000C, 0x8008C, 0x8004C, 0x800CC, 0x8002C, 0x800AC, 0x8006C, 0x800EC, 0x8001C, 0x8009C, 0x8005C, 0x800DC, 0x8003C, 0x800BC, 0x8007C, 0x800FC, 0x80002, 0x80082, 0x80042, 0x800C2, 0x80022, 0x800A2, 0x80062, 0x800E2, 0x80012, 0x80092, 0x80052, 0x800D2, 0x80032, 0x800B2, 0x80072, 0x800F2, 0x8000A, 0x8008A, 0x8004A, 0x800CA, 0x8002A, 0x800AA, 0x8006A, 0x800EA, 0x8001A, 0x8009A, 0x8005A, 0x800DA, 0x8003A, 0x800BA, 0x8007A, 0x800FA, 0x80006, 0x80086, 0x80046, 0x800C6, 0x80026, 0x800A6, 0x80066, 0x800E6, 0x80016, 0x80096, 0x80056, 0x800D6, 0x80036, 0x800B6, 0x80076, 0x800F6, 0x8000E, 0x8008E, 0x8004E, 0x800CE, 0x8002E, 0x800AE, 0x8006E, 0x800EE, 0x8001E, 0x8009E, 0x8005E, 0x800DE, 0x8003E, 0x800BE, 0x8007E, 0x800FE, 0x80001, 0x80081, 0x80041, 0x800C1, 0x80021, 0x800A1, 0x80061, 0x800E1, 0x80011, 0x80091, 0x80051, 0x800D1, 0x80031, 0x800B1, 0x80071, 0x800F1, 0x80009, 0x80089, 0x80049, 0x800C9, 0x80029, 0x800A9, 0x80069, 0x800E9, 0x80019, 0x80099, 0x80059, 0x800D9, 0x80039, 0x800B9, 0x80079, 0x800F9, 0x80005, 0x80085, 0x80045, 0x800C5, 0x80025, 0x800A5, 0x80065, 0x800E5, 0x80015, 0x80095, 0x80055, 0x800D5, 0x80035, 0x800B5, 0x80075, 0x800F5, 0x8000D, 0x8008D, 0x8004D, 0x800CD, 0x8002D, 0x800AD, 0x8006D, 0x800ED, 0x8001D, 0x8009D, 0x8005D, 0x800DD, 0x8003D, 0x800BD, 0x8007D, 0x800FD, 0x90013, 0x90113, 0x90093, 0x90193, 0x90053, 0x90153, 0x900D3, 0x901D3, 0x90033, 0x90133, 0x900B3, 0x901B3, 0x90073, 0x90173, 0x900F3, 0x901F3, 0x9000B, 0x9010B, 0x9008B, 0x9018B, 0x9004B, 0x9014B, 0x900CB, 0x901CB, 0x9002B, 0x9012B, 0x900AB, 0x901AB, 0x9006B, 0x9016B, 0x900EB, 0x901EB, 0x9001B, 0x9011B, 0x9009B, 0x9019B, 0x9005B, 0x9015B, 0x900DB, 0x901DB, 0x9003B, 0x9013B, 0x900BB, 0x901BB, 0x9007B, 0x9017B, 0x900FB, 0x901FB, 0x90007, 0x90107, 0x90087, 0x90187, 0x90047, 0x90147, 0x900C7, 0x901C7, 0x90027, 0x90127, 0x900A7, 0x901A7, 0x90067, 0x90167, 0x900E7, 0x901E7, 0x90017, 0x90117, 0x90097, 0x90197, 0x90057, 0x90157, 0x900D7, 0x901D7, 0x90037, 0x90137, 0x900B7, 0x901B7, 0x90077, 0x90177, 0x900F7, 0x901F7, 0x9000F, 0x9010F, 0x9008F, 0x9018F, 0x9004F, 0x9014F, 0x900CF, 0x901CF, 0x9002F, 0x9012F, 0x900AF, 0x901AF, 0x9006F, 0x9016F, 0x900EF, 0x901EF, 0x9001F, 0x9011F, 0x9009F, 0x9019F, 0x9005F, 0x9015F, 0x900DF, 0x901DF, 0x9003F, 0x9013F, 0x900BF, 0x901BF, 0x9007F, 0x9017F, 0x900FF, 0x901FF, 0x70000, 0x70040, 0x70020, 0x70060, 0x70010, 0x70050, 0x70030, 0x70070, 0x70008, 0x70048, 0x70028, 0x70068, 0x70018, 0x70058, 0x70038, 0x70078, 0x70004, 0x70044, 0x70024, 0x70064, 0x70014, 0x70054, 0x70034, 0x70074, 0x80003, 0x80083, 0x80043, 0x800C3, 0x80023, 0x800A3, 0x80063, 0x800E3, 0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000C, 0x5001C, 0x50002, 0x50012, 0x5000A, 0x5001A, 0x50006, 0x50016, 0x5000E, 0x5001E, 0x50001, 0x50011, 0x50009, 0x50019, 0x50005, 0x50015, 0x5000D, 0x5001D, 0x50003, 0x50013, 0x5000B, 0x5001B, 0x50007, 0x50017
};
void test() {
//    最终结果
//    CC840A00  75 8F 3E 3C 9C 5C E1 79  2D 3B 25 93 12 B6 A9 8A  u.><.\...;%.....
//    CC840A10  40 59 AB 04 B1 7A 25 73  00 74 69 76 69 74 79 00  @Y...z%s.tivity.
 
    char input[0x19] = {0x65, 0x6c, 0x44, 0x49, 0x6b, 0x62, 0x61, 0x4b, 0x69, 0x74, 0x5f, 0x70, 0x65, 0x64, 0x69, 0x79, 0x5f, 0x69, 0x6d, 0x79, 0x61, 0x6e, 0x67, 0x5f, 0x00};
    //char input[0x19] = {0x6a,0x6b,0x4c,0x4d,0x6e,0x6f,0x60,0x41,0x62,0x73,0x54,0x75,0x66,0x67,0x68,0x79,0x5a,0x6b,0x6c,0x7d,0x6e,0x6f,0x60,0x51};
 
    char output[0x64] = {0};
 
 
//    d65df440  4b cd 71 f1 cc 4e 4a f4 ce 2c 89 2f 48 4d c9 ac  K.q..NJ..,./HM..
//    d65df450  8c cf cc ad 4c cc 4b 8f 07 00 00 00 00 00 00 00  ....L.K.........
 
    unsigned char inputTmp[0x19] = {0x78, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
 
    int i = 0;
 
    for(int i = 0; i<strlen(input); i = i+2) {
        unsigned short* tbTmp = (unsigned short*)&ary[input[i]];
        unsigned short t1 = tbTmp[0];
        unsigned short t2 = tbTmp[1];
 
        unsigned int v10 = 0; //   ????
        unsigned int v18 = 0x0003;   //?????
        unsigned int v115 = t1;    //取表下面 D489ABE6
        unsigned int v110 = t2;
 
        if(i - 1 >= 0) {
            tbTmp = (unsigned short*)&ary[input[i - 1]];
            t1 = tbTmp[0];
            t2 = tbTmp[1];
        }
 
        unsigned int v15 = t1;
 
        unsigned int v19 = i - 1 >= 0 ? (v15 >> (16 - (v110 + v18))) : 0x3//D489A6DC+C32
        unsigned int v109 = ((v115 << v18) & v10 | v10 ^ (v115 << v18))^v19;  //D489B10C
 
        tbTmp = (unsigned short*)&ary[input[i + 1]];
        t1 = tbTmp[0];
        t2 = tbTmp[1];
 
        unsigned short v116 = t2;  //取表上面   0x008   D489ABFC
        unsigned int v63 = 0x0003;    //D489B31E    ??????
        unsigned int v118 = v63 + v116; //0x000B    D489B118
        unsigned int v70 = t1;    //取表下面
        unsigned int v71 = (v70 << v118) & v109 | v109 ^ (v70 << v118);  //D489B2D4
        tbTmp = (unsigned short*)&v71;
        t1 = tbTmp[0];
        t2 = tbTmp[1];
        LOGI("xxxxxxxTmp %0x  %0x", t1, t2);
        memcpy(inputTmp + i + 2, &t1, 2);
    }
 
    for(int i = 0; i<strlen(input); i++) {
        LOGI("xxxxxxx %0x", inputTmp[i]);
    }
 
 
//    CC840A00  78 DA 4B CD 71 F1 CC 4E  4A F4 CE 2C 89 2F 48 4D  x............/HM
//    CC840A10  C9 AC 8C CF CC AD 4C CC  00 74 69 76 69 74 79 00  ɬ ....L..tivity.
//    unsigned char temp[0x64] = {0x78, 0xDA, 0x4B, 0xCD, 0x71, 0xF1, 0xCC, 0x4E, 0x4A, 0xF4, 0xCE, 0x2C, 0x89, 0x2F, 0x48, 0x4D, 0xC9, 0xAC, 0x8C, 0xCF, 0xCC, 0xAD, 0x4C, 0xCC};
 
    for(int i = 2; i < 0x18; i++){
        int v94 = ((inputTmp[i] & 0x64) + (~inputTmp[i] & 0x9B)) ^ (((2 * output[i-1] + 117) & 0x64)
                                                            + (~(2 * output[i-1] + 117) & 0x9B));
        output[i] = v94;
        LOGI("v94 = : %0x\n", v94);
    }
 
    output[0] = 0x75;
    output[1] = 0x8f;
}

恭喜ID[飞翔的猫咪]获看雪安卓应用安全能力认证高级安全工程师!!

上传的附件:
收藏
点赞2
打赏
分享
最新回复 (6)
雪    币: 6018
活跃值: 活跃值 (2146)
能力值: ( LV6,RANK:96 )
在线值:
发帖
回帖
粉丝
Imyang 活跃值 1 2020-11-7 14:01
2
0

逆向分析被ollvm混淆的算法的通用过程,使用Frida hook固定所有随机变量,使得输入一个参数能得到唯一的输出结果。 Frida hook Native定位到数据加密的关键函数,再使用trace分析出加密函数的执行过程,由此分析整个算法源码。

本道题是基于zlib进行了少量魔改的算法,本意是想考察如何快速分析魔改的开源代码,没想到咸鱼炒白菜同学把整个算法都分析出来了。


下面是算法原貌

文中sub_011094对应的函数compress2

int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
    Bytef *dest;
    uLongf *destLen;
    const Bytef *source;
    uLong sourceLen;
    int level;
{
    //。。。省略部分compress2原来的代码
    *destLen = stream.total_out;
    deflateEnd(&stream);


    unsigned char r2 = 0x75;
    unsigned char r5 = 0;
    unsigned char r4 = r5 + (r5 << 1);

    for (int i = 2; i < *destLen; ++i) {
        unsigned char r6 = dest[i];

        r4 = r2 + (r4 << 1);
        r4 = r4 ^ r6;
        dest[i] = r4;
    }
    dest[0] = 0x75;
    dest[1] = 0x8F;
    return err == Z_STREAM_END ? Z_OK : err;
}


最后于 2020-11-7 14:06 被Imyang编辑 ,原因:
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_mnqvyswo 活跃值 2020-11-11 17:59
3
0
666
雪    币: 1704
活跃值: 活跃值 (2914)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
kzzll 活跃值 2020-11-12 09:04
4
0
非常棒的分析,对初学来说受益匪浅。
雪    币: 993
活跃值: 活跃值 (375)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
上海刘一刀 活跃值 2 2020-11-12 10:11
5
0
厉害了菜菜大佬
雪    币: 39
活跃值: 活跃值 (473)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
iceway 活跃值 2020-12-10 11:52
6
0
trace是怎么用的?
雪    币: 601
活跃值: 活跃值 (1478)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
kakasasa 活跃值 2021-3-26 14:54
7
0
mark
游客
登录 | 注册 方可回帖
返回