S18 发表于 2019-5-7 14:29

2019看雪CTF_晋级赛Q1_第二题_变形金钢

本帖最后由 S18 于 2019-5-7 14:44 编辑

一直以来都想提高一下逆向能力,但工作比较忙。最近正好有点时间,逆向一个小程序。这个是看雪CTF中的一道题,难度不大,比较适合我这种逆向渣来练手。论坛里面如果有想提高SO逆向的新手朋友,可以看看这道题,我觉得比较适合新人练手。

样本APK在附件中。

反编译APK,可以看到在com.zhuotong.crackme.MainActivity的onCreate函数和android.support.v7.app.AppCompiatActivity的onStart函数中都设置了登陆按钮的响应函数。但是MainActivity继承AppCompiatActivity,MainActivity没有重写onStart,并且Activity的生命周期函数onStart在onCreate之后执行,所以只要看AppCompiatActivity的onStart函数就可以了。
public class AppCompiatActivity extends AppCompatActivity {
    public static final int MSG_LOGIN = 0;
    private Handler handler;
    private Button login;
    private String mName;
    private String mPassword;
    private EditText name;
    private EditText password;

    public native boolean eq(String str);

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

    /* Access modifiers changed, original: protected */
    public void onStart() {
      super.onStart();
      this.login = (Button) findViewById(R.id.login_button);
      this.login.setOnClickListener(new OnClickListener() {
            public void onClick(View view) {
                AppCompiatActivity.this.mName = AppCompiatActivity.this.name.getText().toString();
                AppCompiatActivity.this.mPassword = AppCompiatActivity.this.password.getText().toString();
                if (TextUtils.isEmpty(AppCompiatActivity.this.mName) || TextUtils.isEmpty(AppCompiatActivity.this.mPassword)) {
                  Toast.makeText(AppCompiatActivity.this, "用户名或密码为空", 1).show();
                  return;
                }
                int i = 0;
                AppCompiatActivity.this.login.setEnabled(false);
                if (AppCompiatActivity.this.eq(AppCompiatActivity.this.mPassword)) {
                  ...
                } else {
                  Toast.makeText(AppCompiatActivity.this, "error", 1).show();
                }
            }
      });
      this.name = (EditText) findViewById(R.id.name);
      this.name.setEnabled(false);
      this.password = (EditText) findViewById(R.id.password);
    }
    ...
}
核心逻辑在liboo000oo.so的eq函数里。

liboo000oo.so有一个init函数.datadiv_decode5009363700628197108,在该so被加载时会首先执行,作用是解密几个字符串,包括:

[*](1) "650f909c-7217-3647-9331-c82df8b98e98"
[*](2) "!:#$%&()+-*/`~_[]{}?<>,.@^abcdefghijklmnopqrstuvwxyz0123456789';"
[*](3) "android/support/v7/app/AppCompiatActivity"
[*](4) "eq"
[*](5) "(Ljava/lang/String;)Z"

在后面的分析中可以看到:

[*]字符串(1)经过一系列变换后,作为rc4的key。
[*]字符串(2)作为base64的字符表。
[*]字符串(3)、(4)、(5)在注册android.support.v7.app.AppCompiatActivity的eq函数时用到。

下面贴一下.datadiv_decode5009363700628197108函数的代码,具体看注释:
.text:00000B4C               EXPORT .datadiv_decode5009363700628197108
.text:00000B4C .datadiv_decode5009363700628197108      ; CODE XREF: j_.datadiv_decode5009363700628197108+8↑j
.text:00000B4C                                       ; DATA XREF: LOAD:00000220↑o ...
.text:00000B4C               LDR             R1, =(byte_4020 - 0xB54)
.text:00000B4E               MOVS            R0, #0
.text:00000B50               ADD             R1, PC; byte_4020
.text:00000B52
.text:00000B52 loc_B52                                 ; CODE XREF: .datadiv_decode5009363700628197108+12↓j
.text:00000B52               LDRB            R2,
.text:00000B54               EOR.W         R2, R2, #0xA5 ; 循环异或解密,最后:byte_4020="650f909c-7217-3647-9331-c82df8b98e98"
.text:00000B58               STRB            R2,
.text:00000B5A               ADDS            R0, #1
.text:00000B5C               CMP             R0, #0x25 ; '%'
.text:00000B5E               BNE             loc_B52
.text:00000B60               LDR             R1, =(byte_4050 - 0xB68)
.text:00000B62               MOVS            R0, #0
.text:00000B64               ADD             R1, PC; byte_4050
.text:00000B66
.text:00000B66 loc_B66                                 ; CODE XREF: .datadiv_decode5009363700628197108+26↓j
.text:00000B66               LDRB            R2,
.text:00000B68               EOR.W         R2, R2, #0xA5 ; 循环异或解密,最后:byte_4050="!:#$%&()+-*/`~_[]{}?<>,.@^abcdefghijklmnopqrstuvwxyz0123456789\';"
.text:00000B6C               STRB            R2,
.text:00000B6E               ADDS            R0, #1
.text:00000B70               CMP             R0, #0x42 ; 'B'
.text:00000B72               BNE             loc_B66
.text:00000B74               LDR             R1, =(byte_40A0 - 0xB7C)
.text:00000B76               MOVS            R0, #0
.text:00000B78               ADD             R1, PC; byte_40A0
.text:00000B7A
.text:00000B7A loc_B7A                                 ; CODE XREF: .datadiv_decode5009363700628197108+3A↓j
.text:00000B7A               LDRB            R2,
.text:00000B7C               EOR.W         R2, R2, #0x84 ; 循环异或解密,最后:byte_40A0="android/support/v7/app/AppCompiatActivity"
.text:00000B80               STRB            R2,
.text:00000B82               ADDS            R0, #1
.text:00000B84               CMP             R0, #0x2A ; '*'
.text:00000B86               BNE             loc_B7A
.text:00000B88               PUSH            {R4-R6,LR}
.text:00000B8A               LDR             R1, =(byte_40CA - 0xB92)
.text:00000B8C               LDR             R0, =(byte_40D0 - 0xB94)
.text:00000B8E               ADD             R1, PC; byte_40CA ; 异或解密byte_40CA开始的3个字节,结果:byte_40CA="eq"
.text:00000B90               ADD             R0, PC; byte_40D0 ; 异或解密byte_40D0开始的22个字节,结果:byte_40D0="(Ljava/lang/String;)Z"
.text:00000B92               LDRB            R2,
.text:00000B94               LDRB            R3,
.text:00000B96               EOR.W         R2, R2, #0xFC
.text:00000B9A               LDRB.W          R12,
.text:00000B9E               STRB            R2,
.text:00000BA0               EOR.W         R2, R3, #0xFC
.text:00000BA4               LDRB            R3,
.text:00000BA6               LDRB.W          LR,
.text:00000BAA               STRB            R2,
.text:00000BAC               EOR.W         R2, R12, #0xFC
.text:00000BB0               STRB            R2,
.text:00000BB2               EOR.W         R1, R3, #0x62
.text:00000BB6               LDRB            R4,
.text:00000BB8               LDRB            R2,
.text:00000BBA               LDRB            R6,
.text:00000BBC               LDRB            R5,
.text:00000BBE               EOR.W         R2, R2, #0x62
.text:00000BC2               LDRB.W          R12,
.text:00000BC6               STRB            R1,
.text:00000BC8               EOR.W         R1, LR, #0x62
.text:00000BCC               STRB            R1,
.text:00000BCE               EOR.W         R1, R4, #0x62
.text:00000BD2               STRB            R1,
.text:00000BD4               EOR.W         R1, R6, #0x62
.text:00000BD8               STRB            R1,
.text:00000BDA               EOR.W         R1, R5, #0x62
.text:00000BDE               STRB            R1,
.text:00000BE0               EOR.W         R1, R12, #0x62
.text:00000BE4               STRB            R1,
.text:00000BE6               LDRB            R1,
.text:00000BE8               LDRB            R3,
.text:00000BEA               EOR.W         R1, R1, #0x62
.text:00000BEE               STRB            R2,
.text:00000BF0               STRB            R1,
.text:00000BF2               EOR.W         R1, R3, #0x62
.text:00000BF6               STRB            R1,
.text:00000BF8               LDRB            R1,
.text:00000BFA               EOR.W         R1, R1, #0x62
.text:00000BFE               STRB            R1,
.text:00000C00               LDRB            R1,
.text:00000C02               EOR.W         R1, R1, #0x62
.text:00000C06               STRB            R1,
.text:00000C08               LDRB            R1,
.text:00000C0A               EOR.W         R1, R1, #0x62
.text:00000C0E               STRB            R1,
.text:00000C10               LDRB            R1,
.text:00000C12               EOR.W         R1, R1, #0x62
.text:00000C16               STRB            R1,
.text:00000C18               LDRB            R1,
.text:00000C1A               EOR.W         R1, R1, #0x62
.text:00000C1E               STRB            R1,
.text:00000C20               LDRB            R1,
.text:00000C22               EOR.W         R1, R1, #0x62
.text:00000C26               STRB            R1,
.text:00000C28               LDRB            R1,
.text:00000C2A               EOR.W         R1, R1, #0x62
.text:00000C2E               STRB            R1,
.text:00000C30               LDRB            R1,
.text:00000C32               EOR.W         R1, R1, #0x62
.text:00000C36               STRB            R1,
.text:00000C38               LDRB            R1,
.text:00000C3A               EOR.W         R1, R1, #0x62
.text:00000C3E               STRB            R1,
.text:00000C40               LDRB            R1,
.text:00000C42               EOR.W         R1, R1, #0x62
.text:00000C46               STRB            R1,
.text:00000C48               LDRB            R1,
.text:00000C4A               EOR.W         R1, R1, #0x62
.text:00000C4E               STRB            R1,
.text:00000C50               LDRB            R1,
.text:00000C52               EOR.W         R1, R1, #0x62
.text:00000C56               STRB            R1,
.text:00000C58               LDRB            R1,
.text:00000C5A               EOR.W         R1, R1, #0x62
.text:00000C5E               STRB            R1,
.text:00000C60               POP             {R4-R6,PC}
.text:00000C60 ; End of function .datadiv_decode5009363700628197108
.datadiv_decode5009363700628197108函数执行完之后,会执行JNI_Onload。JNI_Onload函数的代码很简单,就是注册android.support.v7.app.AppCompiatActivity的eq函数。
.text:00000AB4 ; signed int __fastcall JNI_OnLoad(JavaVM *vm)
.text:00000AB4               EXPORT JNI_OnLoad
.text:00000AB4 JNI_OnLoad                              ; DATA XREF: LOAD:00000230↑o
.text:00000AB4
.text:00000AB4 env             = -0x18
.text:00000AB4 var_14          = -0x14
.text:00000AB4 var_10          = -0x10
.text:00000AB4
.text:00000AB4 ; __unwind {
.text:00000AB4               PUSH            {R4-R7,LR}
.text:00000AB6               ADD             R7, SP, #0xC
.text:00000AB8               STR.W         R8, !
.text:00000ABC               SUB             SP, SP, #8
.text:00000ABE               LDR             R1, =(__stack_chk_guard_ptr - 0xACC)
.text:00000AC0               MOV             R8, #0x10004
.text:00000AC8               ADD             R1, PC; __stack_chk_guard_ptr
.text:00000ACA               MOV             R2, R8
.text:00000ACC               LDR             R4, ; __stack_chk_guard
.text:00000ACE               LDR             R1,
.text:00000AD0               STR             R1,
.text:00000AD2               MOVS            R1, #0
.text:00000AD4               STR             R1,
.text:00000AD6               LDR             R1,
.text:00000AD8               LDR             R3, ; R3=GetEnv
.text:00000ADA               MOV             R1, SP
.text:00000ADC               BLX             R3
.text:00000ADE               CBZ             R0, loc_AF8
.text:00000AE0
.text:00000AE0 loc_AE0                                 ; CODE XREF: JNI_OnLoad+68↓j
.text:00000AE0                                       ; JNI_OnLoad+80↓j
.text:00000AE0               MOV.W         R0, #0xFFFFFFFF
.text:00000AE4
.text:00000AE4 loc_AE4                                 ; CODE XREF: JNI_OnLoad+86↓j
.text:00000AE4               LDR             R1,
.text:00000AE6               LDR             R2,
.text:00000AE8               SUBS            R1, R2, R1
.text:00000AEA               ITTT EQ
.text:00000AEC               ADDEQ         SP, SP, #8
.text:00000AEE               LDREQ.W         R8, ,#4
.text:00000AF2               POPEQ         {R4-R7,PC}
.text:00000AF4               BLX             __stack_chk_fail
.text:00000AF8 ; ---------------------------------------------------------------------------
.text:00000AF8
.text:00000AF8 loc_AF8                                 ; CODE XREF: JNI_OnLoad+2A↑j
.text:00000AF8               LDR             R5,
.text:00000AFA               LDR             R0, =(off_4010 - 0xB02)
.text:00000AFC               LDR             R2,
.text:00000AFE               ADD             R0, PC; off_4010
.text:00000B00               LDR             R1, ; byte_40A0 ; R1="android/support/v7/app/AppCompiatActivity"
.text:00000B02               MOV             R0, R5; R0=env
.text:00000B04               LDR             R2, ; R2=FindClass
.text:00000B06               BLX             R2
.text:00000B08               MOV             R6, R0; R6=AppCompiatActivity_clazz
.text:00000B0A               LDR             R0,
.text:00000B0C               MOV             R1, R6; R1=AppCompiatActivity_clazz
.text:00000B0E               LDR             R2, ; R2=NewGlobalRef
.text:00000B10               MOV             R0, R5; R0=env
.text:00000B12               BLX             R2
.text:00000B14               LDR             R1, =(dword_4110 - 0xB1C)
.text:00000B16               CMP             R6, #0
.text:00000B18               ADD             R1, PC; dword_4110
.text:00000B1A               STR             R0,
.text:00000B1C               BEQ             loc_AE0
.text:00000B1E               LDR             R0,
.text:00000B20               MOV             R1, R6; R1=AppCompiatActivity_clazz
.text:00000B22               MOVS            R3, #1
.text:00000B24               LDR.W         R12, ; R12=RegisterNatives
.text:00000B28               MOV             R0, R5
.text:00000B2A               LDR             R2, =(off_4014 - 0xB30)
.text:00000B2C               ADD             R2, PC; off_4014
.text:00000B2E               BLX             R12   ; 注册android.support.v7.app.AppCompiatActivity->eq
.text:00000B30               CMP.W         R0, #0xFFFFFFFF
.text:00000B34               BLE             loc_AE0
.text:00000B36               ADD.W         R0, R8, #2
.text:00000B3A               B               loc_AE4
.text:00000B3A ; End of function JNI_OnLoad
去off_4014看一下eq函数对应liboo000oo.so里的sub_784。
.data:00004014 off_4014      DCD byte_40CA         ; DATA XREF: JNI_OnLoad+78↑o
.data:00004014                                       ; .text:off_B48↑o
.data:00004014                                       ; 指向字符串:"eq"(解密后)
.data:00004018               DCD byte_40D0         ; 指向字符串:"(Ljava/lang/String;)Z"(解密后)
.data:0000401C               DCD sub_784+1
剩下的就是分析核心函数sub_784了。sub_784的逻辑如下:
1. 对之前解密出来的字符串"650f909c-7217-3647-9331-c82df8b98e98"进行逆序,得到"89e89b8f-d28c-1339-7463-7127c909f056"
2. 继续对字符串"89e89b8f-d28c-1339-7463-7127c909f056"进行变换,算法如下:
表1是"dbeafc",表2是"2409715836"
输入是"89e89b8f-d28c-1339-7463-7127c909f056"
依次从字符串中取出一个字符:
如果是数字,则减去0x30('0'),得到的值作为索引,查表"2409715836"
如果是字母,则减去0x61('a'),得到的值作为索引,查表"dbeafc"
如果是'-',则原样存储。
第1个字符'8',减去0x30,得到8,查表"2409715836",得到'3'
第2个字符'9',减去0x30,得到9,查表"2409715836",得到'6'
第3个字符'e',减去0x61,得到4,查表"dbeafc",得到'f'
...
最后变换的结果是:"36f36b3c-a03e-4996-8759-8408e626c215",这个字符串作为后面rc4算法的key。
3. 初始化rc4的状态向量S,内容为:
D7 DF 02 D4 FE 6F 53 3C 25 6C 99 97 06 56 8F DE
40 11 64 07 36 15 70 CA 18 17 7D 6A DB 13 30 37
29 60 E1 23 28 8A 50 8C AC 2F 88 20 27 0F 7C 52
A2 AB FC A1 CC 21 14 1F C2 B2 8B 2C B0 3A 66 46
3D BB 42 A5 0C 75 22 D8 C3 76 1E 83 74 F0 F6 1C
26 D1 4F 0B FF 4C 4D C1 87 03 5A EE A4 5D 9E F4
C8 0D 62 63 3E 44 7B A3 68 32 1B AA 2D 05 F3 F7
16 61 94 E0 D0 D3 98 69 78 E9 0A 65 91 8E 35 85
7A 51 86 10 3F 7F 82 DD B5 1A 95 E7 43 FD 9B 24
45 EF 92 5C E4 96 A9 9C 55 89 9A EA F9 90 5F B8
04 84 CF 67 93 00 A6 39 A8 4E 59 31 6B AD 5E 5B
77 B1 54 DC 38 41 B6 47 9F 73 BA F8 AE C4 BE 34
01 4B 2A 8D BD C5 C6 E8 AF C9 F5 CB FB CD 79 CE
12 71 D2 FA 09 D5 BC 58 19 80 DA 49 1D E6 2E E3
7E B7 3B B3 A0 B9 E5 57 6E D9 08 EB C7 ED 81 F1
F2 BF C0 A7 4A D6 2B B4 72 9D 0E 6D EC 48 E2 33
4. 以"36f36b3c-a03e-4996-8759-8408e626c215"为key,初始化rc4的临时向量T,算法如下:
for i = 0 to 255 do
       T = K;
临时向量T初始化后的结果为:
"36f36b3c-a03e-4996-8759-8408e626c21536f36b3c-a03e-4996-8759-8408"
"e626c21536f36b3c-a03e-4996-8759-8408e626c21536f36b3c-a03e-4996-8"
"759-8408e626c21536f36b3c-a03e-4996-8759-8408e626c21536f36b3c-a03"
"e-4996-8759-8408e626c21536f36b3c-a03e-4996-8759-8408e626c21536f3"
5. 结合前面的临时向量T,重新排列一下状态向量S,算法如下:
j=0;
for i = 0 to 255 do
    j = (j + S + T) mod 256;
    swap(S, S);
6. 接下来就是计算rc4密钥,对输入字符进行rc4加密+base64转码。
计算rc4密钥流的算法如下:
i, j = 0;
for r = 0 to len do//len为明文长度
    i = (i + 1) mod 256;
    j = (j + S) mod 256;
    swap(S, S);
    t = (S + S) mod 256;
    k = S;
base64原理:
base64(3个字节有24个bit,对应4个base64字符):
    M      a      n
010011010110000101101110
{010011}{01 0110}{0001 01}{101110}
索引1    索引2    索引3   索引4
根据4个索引,去查base64字符表
要注意,作者对base64进行了修改。索引1对应的字符异或了0x7,索引3对应的字符异或了0xf。并且要注意最后补的垫字符是';'。
base64字符表也与标准的不同:"!:#$%&()+-*/`~_[]{}?<>,.@^abcdefghijklmnopqrstuvwxyz0123456789\';"

7. 最后,将得到的base64字符串与" {98gal!Tn?@#fj'j$\g;;"进行比对。
下面贴一下sub_784的代码,里面写了详细的注释:
.text:00000784 ; =============== S U B R O U T I N E =======================================
.text:00000784
.text:00000784 ; Attributes: bp-based frame
.text:00000784
.text:00000784 ; int __fastcall sub_784(JNIEnv *env, jobject obj, void *str)
.text:00000784 sub_784                                 ; DATA XREF: .data:0000401C↓o
.text:00000784
.text:00000784 var_234         = -0x234
.text:00000784 var_230         = -0x230
.text:00000784 var_22C         = -0x22C
.text:00000784 var_228         = -0x228
.text:00000784 INPUT         = -0x224
.text:00000784 var_S         = -0x220
.text:00000784 var_T         = -0x120
.text:00000784 var_20          = -0x20
.text:00000784
.text:00000784 ; __unwind {
.text:00000784               PUSH            {R4-R7,LR}
.text:00000786               ADD             R7, SP, #0xC
.text:00000788               PUSH.W          {R8-R11}
.text:0000078C               SUB.W         SP, SP, #0x21C
.text:00000790               LDR             R1, =(__stack_chk_guard_ptr - 0x796)
.text:00000792               ADD             R1, PC; __stack_chk_guard_ptr
.text:00000794               LDR             R1, ; __stack_chk_guard
.text:00000796               STR             R1,
.text:00000798               LDR             R1,
.text:0000079A               STR             R1,
.text:0000079C               LDR             R1,
.text:0000079E               LDR.W         R3, ; R3=GetStringUTFChars
.text:000007A2               MOV             R1, R2
.text:000007A4               MOVS            R2, #0
.text:000007A6               BLX             R3      ; 获取指向输入字符串的char*指针
.text:000007A8               STR             R0,
.text:000007AA               LDR             R0, =(byte_4020 - 0x7B0)
.text:000007AC               ADD             R0, PC; byte_4020 ; R0="650f909c-7217-3647-9331-c82df8b98e98"
.text:000007AE               BLX             strlen
.text:000007B2               MOV             R10, R0 ; R10=24h(R0指向字符串的长度)
.text:000007B4               BLX             malloc; 调用malloc分配3块长度为24h字节的内存,地址分别保存到R6、R8、R11
.text:000007B8               MOV             R6, R0
.text:000007BA               MOV             R0, R10 ; size
.text:000007BC               BLX             malloc
.text:000007C0               MOV             R8, R0
.text:000007C2               MOV             R0, R10 ; size
.text:000007C4               BLX             malloc
.text:000007C8               MOV             R11, R0
.text:000007CA               MOV             R0, R6
.text:000007CC               MOV             R1, R10
.text:000007CE               BLX             __aeabi_memclr ; 调用__aeabi_memclr,将3块新分配的内存清0
.text:000007D2               MOV             R0, R8
.text:000007D4               MOV             R1, R10
.text:000007D6               BLX             __aeabi_memclr
.text:000007DA               MOV             R0, R11
.text:000007DC               MOV             R1, R10
.text:000007DE               BLX             __aeabi_memclr
.text:000007E2               CMP.W         R10, #0
.text:000007E6               BEQ             loc_876
.text:000007E8               LDR             R1, =(byte_4020 - 0x7F2)
.text:000007EA               MOVS            R0, #0; R0=0
.text:000007EC               MOV             R2, R10 ; R2=24h
.text:000007EE               ADD             R1, PC; byte_4020 ; R1="650f909c-7217-3647-9331-c82df8b98e98"
.text:000007F0
.text:000007F0 loc_7F0                                 ; CODE XREF: sub_784+7C↓j
.text:000007F0               LDRB            R3, ; 通过一个小循环,去掉R1指向的字符串中的'-',
.text:000007F0                                       ; 得到"650f909c721736479331c82df8b98e98",保存到R8指向的内存中
.text:000007F2               ADDS            R1, #1
.text:000007F4               CMP             R3, #0x2D ; '-'
.text:000007F6               ITT NE
.text:000007F8               STRNEB.W      R3,
.text:000007FC               ADDNE         R0, #1
.text:000007FE               SUBS            R2, #1
.text:00000800               BNE             loc_7F0
.text:00000802               CMP             R0, #1; R0=20h(字符串"650f909c721736479331c82df8b98e98"的长度)
.text:00000804               BLT             loc_876
.text:00000806               SUBS            R1, R0, #1 ; R1=R0-1=1fh
.text:00000808               MOV             R2, #0xFFFFFFF8
.text:0000080C               MOVS            R3, #0
.text:0000080E               MOV.W         R12, #0x2D ; '-'
.text:00000812               MOVS            R0, #0
.text:00000814
.text:00000814 loc_814                                 ; CODE XREF: sub_784+B4↓j
.text:00000814               ORR.W         R4, R3, R2,LSR#2
.text:00000818               CMP             R4, #3
.text:0000081A               BHI             loc_824
.text:0000081C               ADDS            R4, R0, #1
.text:0000081E               STRB.W          R12,
.text:00000822               B               loc_826
.text:00000824 ; ---------------------------------------------------------------------------
.text:00000824
.text:00000824 loc_824                                 ; CODE XREF: sub_784+96↑j
.text:00000824               MOV             R4, R0
.text:00000826
.text:00000826 loc_826                                 ; CODE XREF: sub_784+9E↑j
.text:00000826               LDRB.W          R0, ; R8="650f909c721736479331c82df8b98e98"
.text:00000826                                       ; R1初始值为1fh,然后减1,也就是依次从此字符串由后向前取字符
.text:0000082A               SUBS            R1, #1
.text:0000082C               ADD.W         R3, R3, #0x40000000
.text:00000830               STRB            R0, ; 通过一个小循环,将最初的字符串("650f909c-7217-3647-9331-c82df8b98e98")逆序,
.text:00000830                                       ; 得到"89e89b8f-d28c-1339-7463-7127c909f056",保存到R6指向的内存中
.text:00000832               ADDS            R2, #1
.text:00000834               ADDS            R0, R4, #1
.text:00000836               ADDS            R5, R1, #1
.text:00000838               BNE             loc_814
.text:0000083A               CMP             R4, #0; R4=23h
.text:0000083C               BLT             loc_876
.text:0000083E               LDR             R1, =(aDbeafc24097158 - 0x848)
.text:00000840               MOV             R3, R11
.text:00000842               LDR             R2, =(aDbeafc24097158+6 - 0x84A)
.text:00000844               ADD             R1, PC; "dbeafc2409715836" ; R1="dbeafc"
.text:00000846               ADD             R2, PC; "2409715836" ; R2="2409715836"
.text:00000846                                       ; 接下来又是一个循环,继续对字符串进行变换
.text:00000846                                       ; 表1是"dbeafc",表2是"2409715836"
.text:00000846                                       ; 输入是"89e89b8f-d28c-1339-7463-7127c909f056"
.text:00000846                                       ; 依次从字符串中取出一个字符:
.text:00000846                                       ; 如果是数字,则减去0x30('0'),得到的值作为索引,查表"2409715836"
.text:00000846                                       ; 如果是字母,则减去0x61('a'),得到的值作为索引,查表"dbeafc"
.text:00000846                                       ; 如果是'-',则原样存储。
.text:00000846                                       ; 第1个字符'8',减去0x30,得到8,查表"2409715836",得到'3'
.text:00000846                                       ; 第2个字符'9',减去0x30,得到9,查表"2409715836",得到'6'
.text:00000846                                       ; 第3个字符'e',减去0x61,得到4,查表"dbeafc",得到'f'
.text:00000846                                       ; ...
.text:00000846                                       ; 最后变换的结果是:"36f36b3c-a03e-4996-8759-8408e626c215"
.text:00000848
.text:00000848 loc_848                                 ; CODE XREF: sub_784+F0↓j
.text:00000848               LDRB            R5, ; R6="89e89b8f-d28c-1339-7463-7127c909f056"
.text:0000084A               SUB.W         R4, R5, #0x61
.text:0000084E               UXTB            R4, R4
.text:00000850               CMP             R4, #5
.text:00000852               BHI             loc_85A
.text:00000854               ADD             R5, R1; 如果是字母,减'a',然后查表R2="dbeafc"
.text:00000856               SUBS            R5, #0x61 ; 'a'
.text:00000858               B               loc_868
.text:0000085A ; ---------------------------------------------------------------------------
.text:0000085A
.text:0000085A loc_85A                                 ; CODE XREF: sub_784+CE↑j
.text:0000085A               SUB.W         R4, R5, #0x30
.text:0000085E               UXTB            R4, R4
.text:00000860               CMP             R4, #9
.text:00000862               BHI             loc_86A
.text:00000864               ADD             R5, R2; 如果是数字,减'0',然后查表R2="2409715836"
.text:00000866               SUBS            R5, #0x30 ; '0'
.text:00000868
.text:00000868 loc_868                                 ; CODE XREF: sub_784+D4↑j
.text:00000868               LDRB            R5, ; 从表中取出转换后的字符
.text:0000086A
.text:0000086A loc_86A                                 ; CODE XREF: sub_784+DE↑j
.text:0000086A               STRB.W          R5, ,#1 ; 变换后的结果,保存在R3指向的内存中
.text:0000086E               SUBS            R0, #1
.text:00000870               ADD.W         R6, R6, #1 ; R6+=1,指向"89e89b8f-d28c-1339-7463-7127c909f056"中的下一个字符
.text:00000874               BNE             loc_848
.text:00000876
.text:00000876 loc_876                                 ; CODE XREF: sub_784+62↑j
.text:00000876                                       ; sub_784+80↑j ...
.text:00000876               LDR             R1, =(unk_23E8 - 0x884)
.text:00000878               ADD.W         R9, SP, #0x238+var_S
.text:0000087C               MOV.W         R2, #0x100
.text:00000880               ADD             R1, PC; unk_23E8
.text:00000882               MOV             R0, R9
.text:00000884               BLX             __aeabi_memcpy8 ; 为栈上的一块256字节大小的buf赋初值,貌似是RC4的状态变量S。
.text:00000884                                       ; 那就暂时将这块内存称为数组S吧,初始内容:
.text:00000884                                       ; D7 DF 02 D4 FE 6F 53 3C25 6C 99 97 06 56 8F DE
.text:00000884                                       ; 40 11 64 07 36 15 70 CA18 17 7D 6A DB 13 30 37
.text:00000884                                       ; 29 60 E1 23 28 8A 50 8CAC 2F 88 20 27 0F 7C 52
.text:00000884                                       ; A2 AB FC A1 CC 21 14 1FC2 B2 8B 2C B0 3A 66 46
.text:00000884                                       ; 3D BB 42 A5 0C 75 22 D8C3 76 1E 83 74 F0 F6 1C
.text:00000884                                       ; 26 D1 4F 0B FF 4C 4D C187 03 5A EE A4 5D 9E F4
.text:00000884                                       ; C8 0D 62 63 3E 44 7B A368 32 1B AA 2D 05 F3 F7
.text:00000884                                       ; 16 61 94 E0 D0 D3 98 6978 E9 0A 65 91 8E 35 85
.text:00000884                                       ; 7A 51 86 10 3F 7F 82 DDB5 1A 95 E7 43 FD 9B 24
.text:00000884                                       ; 45 EF 92 5C E4 96 A9 9C55 89 9A EA F9 90 5F B8
.text:00000884                                       ; 04 84 CF 67 93 00 A6 39A8 4E 59 31 6B AD 5E 5B
.text:00000884                                       ; 77 B1 54 DC 38 41 B6 479F 73 BA F8 AE C4 BE 34
.text:00000884                                       ; 01 4B 2A 8D BD C5 C6 E8AF C9 F5 CB FB CD 79 CE
.text:00000884                                       ; 12 71 D2 FA 09 D5 BC 5819 80 DA 49 1D E6 2E E3
.text:00000884                                       ; 7E B7 3B B3 A0 B9 E5 576E D9 08 EB C7 ED 81 F1
.text:00000884                                       ; F2 BF C0 A7 4A D6 2B B472 9D 0E 6D EC 48 E2 33
.text:00000888               ADD             R4, SP, #0x238+var_T
.text:0000088A               MOVS            R5, #0; 接下来是一个小循环,初始化栈上的(R4指向的)另一块256字节大小的buf。
.text:0000088A                                       ; 貌似是以"36f36b3c-a03e-4996-8759-8408e626c215"为Key,初始化RC4的临时向量T:
.text:0000088A                                       ; for i=0 to 255 do
.text:0000088A                                       ;    T=K;
.text:0000088C
.text:0000088C loc_88C                                 ; CODE XREF: sub_784+11C↓j
.text:0000088C               MOV             R0, R5
.text:0000088E               MOV             R1, R10
.text:00000890               BLX             sub_D20
.text:00000894               LDRB.W          R0, ; 这行指令中的R1,从0-23h,循环变换。
.text:00000894                                       ; 所以R1即上面算法中的“i mod 23h(keylen)”
.text:00000894                                       ; R11="36f36b3c-a03e-4996-8759-8408e626c215"
.text:00000898               STRB            R0, ; 临时向量T,保存在R4指向的内存中。
.text:00000898                                       ; 最后结果为:
.text:00000898                                       ; "36f36b3c-a03e-4996-8759-8408e626c21536f36b3c-a03e-4996-8759-8408"
.text:00000898                                       ; "e626c21536f36b3c-a03e-4996-8759-8408e626c21536f36b3c-a03e-4996-8"
.text:00000898                                       ; "759-8408e626c21536f36b3c-a03e-4996-8759-8408e626c21536f36b3c-a03"
.text:00000898                                       ; "e-4996-8759-8408e626c21536f36b3c-a03e-4996-8759-8408e626c21536f3"
.text:0000089A               ADDS            R5, #1
.text:0000089C               CMP.W         R5, #0x100
.text:000008A0               BNE             loc_88C
.text:000008A2               LDRB.W          R0,
.text:000008A6               SUBS            R0, #0x29 ; ')'
.text:000008A8               UXTB            R0, R0; R0=10
.text:000008AA               LDRB.W          R1, ; R9指向状态向量S,R1=S
.text:000008AE               STRB.W          R1, ; S=S
.text:000008B2               MOVS            R1, #0xD7 ; R1=0xD7
.text:000008B4               STRB.W          R1, ; S=0xD7=S
.text:000008B4                                       ; 上面几行代码,将状态向量S的索引为0和10的两个元素互换了一下。
.text:000008B4                                       ; 相当于是将下面重新排列S算法的第1次循环执行完了,下面的循环直接从第2次循环开始执行。
.text:000008B8               MOVS            R1, #1; 下面是个小循环,结合前面的临时向量T,重新排列一下状态向量S,算法如下:
.text:000008B8                                       ; (1) j=0;
.text:000008B8                                       ; (2) for i=0 to 255 do
.text:000008B8                                       ; (3)    j=(j+S+T) mod 256;
.text:000008B8                                       ; (4)    swap(S,S);
.text:000008BA
.text:000008BA loc_8BA                                 ; CODE XREF: sub_784+15E↓j
.text:000008BA               LDRB.W          R2, ; R2=S:R9指向状态向量S,R1即上面算法中的i,初始值为1。
.text:000008BE               LDRB            R3, ; R3=T:R4指向临时向量T
.text:000008C0               ADD             R3, R2; R3=S+T(对应上述算法中的第3行)
.text:000008C2               ADD             R0, R3; R0=j+S+T(对应上述算法中的第3行)
.text:000008C2                                       ; R0即上面算法中的j,初始值为10
.text:000008C4               ASRS            R3, R0, #0x1F
.text:000008C6               ADD.W         R3, R0, R3,LSR#24
.text:000008CA               BIC.W         R3, R3, #0xFF
.text:000008CE               SUBS            R0, R0, R3 ; R0=(j+S+T) mod 256(对应上述算法中的第3行)
.text:000008D0               LDRB.W          R3, ; R3=S(对应上述算法中的第4行)
.text:000008D4               STRB.W          R3, ; S=S(对应上述算法中的第4行)
.text:000008D8               ADDS            R1, #1; i+=1
.text:000008DA               CMP.W         R1, #0x100
.text:000008DE               STRB.W          R2, ; S=S(对应上述算法中的第4行)
.text:000008E2               BNE             loc_8BA
.text:000008E4               LDR             R0, ; R0指向输入字符串
.text:000008E6               BLX             strlen
.text:000008EA               MOVW            R2, #0xAAAB
.text:000008EE               MOV             R8, R0; R8=输入字符串长度
.text:000008F0               MOVT.W          R2, #0xAAAA
.text:000008F4               LDRB.W          R5, ; R5=0x33
.text:000008F4                                       ; R11="36f36b3c-a03e-4996-8759-8408e626c215"
.text:000008F8               UMULL.W         R0, R1, R8, R2 ; 这块貌似是编译器的除法优化
.text:000008FC               LSRS            R0, R1, #1
.text:000008FE               ADD.W         R1, R8, #3
.text:00000902               ADD.W         R0, R0, R0,LSL#1
.text:00000906               SUB.W         R0, R8, R0
.text:0000090A               SUBS            R0, R1, R0
.text:0000090C               LSLS            R0, R0, #3
.text:0000090E               STR             R0,
.text:00000910               UMULL.W         R0, R1, R0, R2
.text:00000914               ADD.W         R0, R5, R1,LSR#2
.text:00000918               STR             R0,
.text:0000091A               ADDS            R0, #1; size
.text:0000091C               BLX             malloc; 分配一块3Ch大小的内存
.text:00000920               CMP.W         R8, #0; R8=输入字符串长度
.text:00000924               BEQ.W         loc_A46
.text:00000928               MOV.W         R10, #0
.text:0000092C               MOVS            R2, #0
.text:0000092E               MOV.W         R12, #0
.text:00000932               STR             R5,
.text:00000934               B               loc_9A8
.text:00000936 ; ---------------------------------------------------------------------------
.text:00000936
.text:00000936 loc_936                                 ; CODE XREF: sub_784+288↓j
.text:00000936               CMP             R2, #1; R2是明文字符索引
.text:00000938               ITT NE
.text:0000093A               ADDNE.W         R1, LR, #1
.text:0000093E               CMPNE         R1, R2
.text:00000940               BNE             loc_96A
.text:00000942               LDR             R1, ; var_228保存的是一个偏移值,用于计算保存base64编码结果的最后一个字符的位置
.text:00000944               UXTB.W          R6, R11 ; R11=明文字符的RC4加密结果,将其无符号扩展到32bit,赋值给R6
.text:00000948               ADDS            R3, R1, R2 ; R2是明文字符索引
.text:0000094A               LDRB            R4, ; 取出之前保存的“索引2”(只有高2位有效),保存到R4
.text:0000094C               LDR             R1, =(byte_4050 - 0x952)
.text:0000094E               ADD             R1, PC; byte_4050 ; R1="!:#$%&()+-*/`~_[]{}?<>,.@^abcdefghijklmnopqrstuvwxyz0123456789\';"
.text:0000094E                                       ; 这个字符串作为base64字符表
.text:00000950               ORR.W         R4, R4, R6,LSR#4 ; R6逻辑右移4位,再异或R4,得到最终的索引2,结果保存到R4
.text:00000950                                       ; ------------------------------------------------------
.text:00000950                                       ; base64(3个字节有24个bit,对应4个base64字符):
.text:00000950                                       ;   M      a      n
.text:00000950                                       ; 010011010110000101101110
.text:00000950                                       ; {010011}{01 0110}{0001 01}{101110}
.text:00000950                                       ;   索引1   索引2   索引3   索引4
.text:00000950                                       ; ------------------------------------------------------
.text:00000950                                       ; 根据4个索引,去查base64字符表
.text:00000954               LDRB            R4, ; 查表,取出索引2对应的base64字符
.text:00000956               STRB            R4, ; 保存索引2对应的base64字符
.text:00000958               ADDS            R4, R0, R3 ; R4指向保存base64编码结果的最后一个字符位置
.text:0000095A               MOVS            R3, #0b111100
.text:0000095C               AND.W         R3, R3, R6,LSL#2 ; R6=明文字符的RC4加密结果,
.text:0000095C                                       ; 逻辑左移2位,再与0x3C(00111100),清除高2位和低2位
.text:0000095C                                       ; 相当于取R6的低4位,然后左移2位,结果保存到R3
.text:0000095C                                       ; 即R3保存的是索引3的高4位
.text:00000960               ADDS            R6, R2, #1 ; R2是明文字符索引
.text:00000962               CMP             R6, R8; R8=明文字符串长度
.text:00000964               STRB            R3, ; 保存索引3(存储在base64编码结果的最后一个字符的后一个字节,目前只有高4位有效)
.text:00000966               BCC             loc_A34
.text:00000968               B               loc_A82
.text:0000096A ; ---------------------------------------------------------------------------
.text:0000096A
.text:0000096A loc_96A                                 ; CODE XREF: sub_784+1BC↑j
.text:0000096A               CMP             R2, #2
.text:0000096C               ITT NE
.text:0000096E               ADDNE.W         R1, LR, #2
.text:00000972               CMPNE         R1, R2
.text:00000974               BNE             loc_A34
.text:00000976               LDR             R1, =(byte_4050 - 0x984)
.text:00000978               AND.W         R4, R11, #0xC0 ; R11=明文字符的RC4加密结果,
.text:00000978                                       ; 和0xC0(11000000)与,清除低6位,保留高2位,保存到R4
.text:0000097C               LDR.W         LR, ; var_228保存的是一个偏移值,用于计算保存base64编码结果的最后一个字符的位置
.text:00000980               ADD             R1, PC; byte_4050 ; R1="!:#$%&()+-*/`~_[]{}?<>,.@^abcdefghijklmnopqrstuvwxyz0123456789\';"
.text:00000982               ADD.W         R3, LR, R2 ; R2是明文字符索引
.text:00000986               ADD.W         LR, LR, #1
.text:0000098A               STR.W         LR,
.text:0000098E               LDRB            R6, ; 取出之前保存的“索引3”(只有高4位有效),保存到R6
.text:00000990               ORR.W         R6, R6, R4,LSR#6 ; 取R4的高2位,右移6位,与R6进行或操作,得到最终的索引3
.text:00000990                                       ; ------------------------------------------------------
.text:00000990                                       ; base64(3个字节有24个bit,对应4个base64字符):
.text:00000990                                       ;   M      a      n
.text:00000990                                       ; 010011010110000101101110
.text:00000990                                       ; {010011}{01 0110}{0001 01}{101110}
.text:00000990                                       ;   索引1   索引2   索引3   索引4
.text:00000990                                       ; ------------------------------------------------------
.text:00000990                                       ; 根据4个索引,去查base64字符表
.text:00000994               LDRB            R6, ; 查表,取出索引3对应的base64字符
.text:00000996               EOR.W         R6, R6, #0xF ; 对于索引3对应的base64字符,还要再异或一下0xF
.text:0000099A               STRB            R6, ; 保存索引3对应的base64字符
.text:0000099C               AND.W         R6, R11, #0x3F ; R11=明文字符的RC4加密结果,
.text:0000099C                                       ; 和0x3F(00111111)与,清除高2位,保留低6位,得到索引4,保存到R6
.text:000009A0               ADD             R3, R0; R3指向保存base64编码结果的最后一个字符位置
.text:000009A2               LDRB            R1, ; R6是索引4,查表,取出索引4对应的base64字符
.text:000009A4               STRB            R1, ; 保存索引4对应的base64字符
.text:000009A6               B               loc_A34
.text:000009A8 ; ---------------------------------------------------------------------------
.text:000009A8
.text:000009A8 loc_9A8                                 ; CODE XREF: sub_784+1B0↑j
.text:000009A8                                       ; sub_784+2B4↓j
.text:000009A8               ADD.W         R1, R10, #1 ; 接下来这块代码,就是对输入字符做RC4加密
.text:000009A8                                       ; R10即如下产生密钥流算法中的i,R1=i+1(对应第3行)
.text:000009A8                                       ; (1) i,j=0;
.text:000009A8                                       ; (2) for r=0 to len do//len为明文长度
.text:000009A8                                       ; (3)    i=(i+1) mod 256;
.text:000009A8                                       ; (4)    j=(j+S) mod 256;
.text:000009A8                                       ; (5)    swap(S,S);
.text:000009A8                                       ; (6)    t=(S+S) mod 256;
.text:000009A8                                       ; (7)    k=S;
.text:000009AC               CMP             R2, #0; R2是明文字符索引
.text:000009AE               MOV.W         R3, R1,ASR#31 ; 计算"R1 mod 256",结果保存到R10,即R10=(i+1) mod 256;(对应第3行)
.text:000009B2               ADD.W         R3, R1, R3,LSR#24
.text:000009B6               BIC.W         R3, R3, #0xFF
.text:000009BA               SUB.W         R10, R1, R3
.text:000009BE               LDRB.W          R1, ; R9指向状态向量S,取出S(对应第4行中的S)
.text:000009C2               ADD.W         R3, R12, R1 ; R12即如上产生密钥流算法中的j,即R3=j+S(对应第4行)
.text:000009C6               MOV.W         R4, R3,ASR#31 ; 计算"R3 mod 256",结果保存到R12(对应第4行)
.text:000009CA               ADD.W         R4, R3, R4,LSR#24
.text:000009CE               BIC.W         R4, R4, #0xFF
.text:000009D2               SUB.W         R12, R3, R4 ; 即R12=(j+S) mod 256(对应第4行)
.text:000009D6               LDRB.W          R3, ; R9指向状态向量S,从S中取出索引S,即S(对应第5行)
.text:000009DA               STRB.W          R3, ; S=S(对应第5行)
.text:000009DE               STRB.W          R1, ; S=S(对应第5行)
.text:000009E2               LDRB.W          R4, ; R4=S(对应第6行)
.text:000009E6               LDR             R3, ; R3指向明文字符串
.text:000009E8               ADD             R1, R4; R1=S+S(对应第6行)
.text:000009EA               LDRB            R3, ; 取出一个明文字符
.text:000009EC               UXTB            R1, R1; 利用UXTB做mod256运算,即R1=(S+S) mod 256;(对应第6行)
.text:000009EE               LDRB.W          R1, ; R1=S,即取出密钥流中的一个密钥字节(对应第7行)
.text:000009F2               EOR.W         R11, R1, R3 ; R11=R1^R3,即该明文字符的RC4加密结果
.text:000009F6               BEQ             loc_A0E
.text:000009F8               MOV             R1, #0xAAAAAAAB
.text:00000A00               UMULL.W         R1, R3, R2, R1 ; R2是明文字符索引,这块的乘法可能是编译器做的除法优化
.text:00000A04               LSRS            R1, R3, #1
.text:00000A06               ADD.W         LR, R1, R1,LSL#1
.text:00000A0A               CMP             LR, R2
.text:00000A0C               BNE             loc_936
.text:00000A0E
.text:00000A0E loc_A0E                                 ; CODE XREF: sub_784+272↑j
.text:00000A0E               LDR             R1, =(byte_4050 - 0xA1C)
.text:00000A10               UXTB.W          R3, R11 ; R11是明文字符的RC4加密结果,赋给R3
.text:00000A14               LSRS            R4, R3, #2 ; R3逻辑右移2位,结果保存到R4,得到索引1
.text:00000A14                                       ; ------------------------------------------------------
.text:00000A14                                       ; base64(3个字节有24个bit,对应4个base64字符):
.text:00000A14                                       ;   M      a      n
.text:00000A14                                       ; 010011010110000101101110
.text:00000A14                                       ; {010011}{01 0110}{0001 01}{101110}
.text:00000A14                                       ;   索引1    索引2    索引3   索引4
.text:00000A14                                       ; ------------------------------------------------------
.text:00000A14                                       ; 根据4个索引,去查base64字符表
.text:00000A16               LDR             R6, ; var_228保存的是一个偏移值,用于计算保存base64编码结果的最后一个字符的位置
.text:00000A18               ADD             R1, PC; byte_4050 ; R1="!:#$%&()+-*/`~_[]{}?<>,.@^abcdefghijklmnopqrstuvwxyz0123456789\';"
.text:00000A1A               ADD             R6, R2; R2是明文字符索引
.text:00000A1C               LDRB            R4, ; 查表,取出索引1对应的base64字符
.text:00000A1E               EOR.W         R4, R4, #7 ; 对于索引1对应的base64字符,还要再异或一下0x7
.text:00000A22               STRB            R4, ; 保存索引1对应的base64字符
.text:00000A24               ADDS            R4, R0, R6 ; R4指向保存base64编码结果的最后一个字符位置
.text:00000A26               MOVS            R6, #0x30 ; '0'
.text:00000A28               AND.W         R3, R6, R3,LSL#4 ; R3是明文字符的RC4加密结果,先逻辑左移4位,再异或00110000。
.text:00000A28                                       ; 即取R3的低2位,然后左移4位,得到索引2的高2位
.text:00000A2C               ADDS            R6, R2, #1 ; R2是明文字符索引,加1赋给R6
.text:00000A2E               STRB            R3, ; 保存索引2(存储在base64编码结果的最后一个字符的后一个字节,目前只有高2位有效)
.text:00000A30               CMP             R6, R8; R8=明文字符串长度
.text:00000A32               BCS             loc_A3C ; 如果R6>=R8,跳转到loc_A3C
.text:00000A34
.text:00000A34 loc_A34                                 ; CODE XREF: sub_784+1E2↑j
.text:00000A34                                       ; sub_784+1F0↑j ...
.text:00000A34               ADDS            R2, #1; R2+=1
.text:00000A36               CMP             R2, R8; R2=明文字符串索引,R8=明文字符串长度
.text:00000A38               BCC             loc_9A8 ; 如果R2<R8,跳转到loc_9A8
.text:00000A3A               B               loc_A46
.text:00000A3C ; ---------------------------------------------------------------------------
.text:00000A3C
.text:00000A3C loc_A3C                                 ; CODE XREF: sub_784+2AE↑j
.text:00000A3C               LDRB            R1,
.text:00000A3E               MOVW            R2, #0x3B3B ; 在最后补';;',相当于标准base64的'=='
.text:00000A3E                                       ; 因为最后一个base索引缺4bit,需要补两个'='
.text:00000A42               STRH            R2,
.text:00000A44
.text:00000A44 loc_A44                                 ; CODE XREF: sub_784+304↓j
.text:00000A44               STRB            R1, ; 保存最后一个base64字符
.text:00000A46
.text:00000A46 loc_A46                                 ; CODE XREF: sub_784+1A0↑j
.text:00000A46                                       ; sub_784+2B6↑j
.text:00000A46               LDR             R1,
.text:00000A48               CBZ             R1, loc_A66
.text:00000A4A               LDR             R2, =(a98gaLTnFjJG - 0xA54)
.text:00000A4C               MOVS            R1, #1; R1=1
.text:00000A4E               LDR             R4,
.text:00000A50               ADD             R2, PC; " {9*8ga*l!Tn?@#fj'j$\\g;;" ; R2=" {9*8ga*l!Tn?@#fj'j$\\g;;"
.text:00000A52
.text:00000A52 loc_A52                                 ; CODE XREF: sub_784+2DE↓j
.text:00000A52               LDRB            R3, ; 下面是一个循环,比较最后的base64字符串和" {9*8ga*l!Tn?@#fj'j$\\g;;"
.text:00000A54               ADDS            R5, #1
.text:00000A56               LDRB.W          R6, ,#1 ; " {9*8ga*l!Tn?@#fj'j$\\g;;"
.text:00000A5A               CMP             R6, R3
.text:00000A5C               IT NE
.text:00000A5E               MOVNE         R1, #0; 如果不相等,R0=0(结果失败)
.text:00000A60               CMP             R5, R4
.text:00000A62               BCC             loc_A52
.text:00000A64               B               loc_A68
.text:00000A66 ; ---------------------------------------------------------------------------
.text:00000A66
.text:00000A66 loc_A66                                 ; CODE XREF: sub_784+2C4↑j
.text:00000A66               MOVS            R1, #1
.text:00000A68
.text:00000A68 loc_A68                                 ; CODE XREF: sub_784+2E0↑j
.text:00000A68               LDR             R0, ; 后面是堆栈检查,不用看了
.text:00000A6A               LDR             R2,
.text:00000A6C               LDR             R2,
.text:00000A6E               SUBS            R0, R2, R0
.text:00000A70               ITTTT EQ
.text:00000A72               UXTBEQ          R0, R1
.text:00000A74               ADDEQ.W         SP, SP, #0x21C
.text:00000A78               POPEQ.W         {R8-R11}
.text:00000A7C               POPEQ         {R4-R7,PC}
.text:00000A7E               BLX             __stack_chk_fail
.text:00000A82 ; ---------------------------------------------------------------------------
.text:00000A82
.text:00000A82 loc_A82                                 ; CODE XREF: sub_784+1E4↑j
.text:00000A82               LDRB            R1, ; 查表取出最后一个base64字符(最后一个base64索引可能不足6位)
.text:00000A84               MOVS            R2, #0x34 ; '4'
.text:00000A86               STRB            R2, ; 在base64编码结果的最后加个'4'。
.text:00000A86                                       ; R4目前指向保存base64编码结果的倒数第2个字符位置
.text:00000A88               B               loc_A44
.text:00000A88 ; End of function sub_784
把sub_784函数分析清楚之后,就可以写出破解脚本了:
# 最后的结果是base64字符串:" {9*8ga*l!Tn?@#fj'j$\\g;;"
str_result = " {9*8ga*l!Tn?@#fj'j$\\g;;"
print 'str_result=' + str_result

# 作者在base64时,将索引1和索引3对应的字符分别异或了0x7和0xf
# 所以先将base64字符串还原回异或之前的样子
# 最后的两个';;',是后补的垫字符,相当于标准base64的'==',不参与异或还原
str_base64 = ''
for i in range(len(str_result)):
    if str_result == ';':
      str_base64 += ';'
    elif i % 4 == 0:
      str_base64 += chr(ord(str_result) ^ 0x7)
    elif i % 4 == 2:
      str_base64 += chr(ord(str_result) ^ 0xf)
    else:
      str_base64 += str_result
print 'str_base64=' + str_base64

# 作者的base64字符表是非标准的,先将str_base64转换回标准base64字符串
base64_chars = "!:#$%&()+-*/`~_[]{}?<>,.@^abcdefghijklmnopqrstuvwxyz0123456789\\';"
base64_chars_std = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
tab = string.maketrans(base64_chars, base64_chars_std)
str_base64_std = str_base64.translate(tab)
print 'str_base64_std=' + str_base64_std

# 利用标准的base64算法进行解码
str_base64_decode = str_base64_std.decode('base64')
#print_hex(str_base64_decode) # fd 1e 8a 4e 09 ca 90 03 e7 f1 85 9f 9b f7 83 3e

# rc4状态向量S
rc4_S = bytearray('D7DF02D4FE6F533C256C999706568FDE'
                  '40116407361570CA18177D6ADB133037'
                  '2960E123288A508CAC2F8820270F7C52'
                  'A2ABFCA1CC21141FC2B28B2CB03A6646'
                  '3DBB42A50C7522D8C3761E8374F0F61C'
                  '26D14F0BFF4C4DC187035AEEA45D9EF4'
                  'C80D62633E447BA368321BAA2D05F3F7'
                  '166194E0D0D3986978E90A65918E3585'
                  '7A5186103F7F82DDB51A95E743FD9B24'
                  '45EF925CE496A99C55899AEAF9905FB8'
                  '0484CF679300A639A84E59316BAD5E5B'
                  '77B154DC3841B6479F73BAF8AEC4BE34'
                  '014B2A8DBDC5C6E8AFC9F5CBFBCD79CE'
                  '1271D2FA09D5BC581980DA491DE62EE3'
                  '7EB73BB3A0B9E5576ED908EBC7ED81F1'
                  'F2BFC0A74AD62BB4729D0E6DEC48E233'.decode("hex"))
#print_hex2(rc4_S)

rc4_KEY = '36f36b3c-a03e-4996-8759-8408e626c215'
# rc4临时向量T
rc4_T = []
for i in range(256):
    rc4_T += rc4_KEY
#print rc4_T

# 重新排列状态向量S
j = 0
for i in range(256):
    j = (j + rc4_S + ord(rc4_T)) % 256
    rc4_S, rc4_S = rc4_S, rc4_S
print_hex2(rc4_S) # f0 37 e1 9b 2a 15 17 9f d7 58 4d 6e 33 a0 39 ae

# 利用rc4解密回应该输入的字符串
str_input = ''
i = j = 0
for e in str_base64_decode:
    i = (i + 1) % 256
    j = (j + rc4_S) %256
    rc4_S, rc4_S = rc4_S, rc4_S
    t = (rc4_S + rc4_S) % 256;
    str_input += chr(ord(e) ^ rc4_S)
print 'str_input=' + str_input
运行得到:fu0kzHp2aqtZAuY6
文/十八垧

闲月疏云 发表于 2019-5-7 17:05

比较适合我这种逆向渣来练手
出类拔萃Rank: 4
精华2
威望17 点
我差点信了你的鬼话.jpg

lemniscate 发表于 2019-5-10 14:03

还有一个问题:
.text:000007AC               ADD             R0, PC; byte_4020 ; R0="650f909c-7217-3647-9331-c82df8b98e98"
.text:000007AE               BLX             strlen
.text:000007B2               MOV             R10, R0 ; R10=24h(R0指向字符串的长度)
这个r10不是36么

Loveherk 发表于 2019-5-7 15:06

我是不是第一个来看的,虽然啥也看不懂,大佬能不能给我推荐一下如果要学这东西的话,开端在哪

loonglee 发表于 2019-5-7 15:13

欢迎分析讨论交流,吾爱破解论坛有你更精彩!

_默默_ 发表于 2019-5-7 15:21

大哥你这样做题一般得做多久,汇编一句句的的看也太难了吧

AmIzero 发表于 2019-5-7 16:20

python大法好

Pingerfy 发表于 2019-5-7 16:30

Loveherk 发表于 2019-5-7 15:06
我是不是第一个来看的,虽然啥也看不懂,大佬能不能给我推荐一下如果要学这东西的话,开端在哪

论坛有出过系列教程的 可以搜一下

血色天空 发表于 2019-5-7 17:12

楼主厉害,我脑袋都看云了

cat95f 发表于 2019-5-7 17:29

是编程吗?太难学

Y阿奴 发表于 2019-5-7 17:33

看得懂代码,然并卵。。
页: [1] 2 3 4 5 6 7 8
查看完整版本: 2019看雪CTF_晋级赛Q1_第二题_变形金钢