吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 27802|回复: 72
上一主题 下一主题
收起左侧

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

  [复制链接]
跳转到指定楼层
楼主
S18 发表于 2019-5-7 14:29 回帖奖励
本帖最后由 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函数就可以了。
[Java] 纯文本查看 复制代码
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函数的代码,具体看注释:
[Asm] 纯文本查看 复制代码
.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, [R1,R0]
.text:00000B54                 EOR.W           R2, R2, #0xA5 ; 循环异或解密,最后:byte_4020="650f909c-7217-3647-9331-c82df8b98e98"
.text:00000B58                 STRB            R2, [R1,R0]
.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, [R1,R0]
.text:00000B68                 EOR.W           R2, R2, #0xA5 ; 循环异或解密,最后:byte_4050="!:#$%&()+-*/`~_[]{}?<>,.@^abcdefghijklmnopqrstuvwxyz0123456789\';"
.text:00000B6C                 STRB            R2, [R1,R0]
.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, [R1,R0]
.text:00000B7C                 EOR.W           R2, R2, #0x84 ; 循环异或解密,最后:byte_40A0="android/support/v7/app/AppCompiatActivity"
.text:00000B80                 STRB            R2, [R1,R0]
.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, [R1]
.text:00000B94                 LDRB            R3, [R1,#(byte_40CB - 0x40CA)]
.text:00000B96                 EOR.W           R2, R2, #0xFC
.text:00000B9A                 LDRB.W          R12, [R1,#(byte_40CC - 0x40CA)]
.text:00000B9E                 STRB            R2, [R1]
.text:00000BA0                 EOR.W           R2, R3, #0xFC
.text:00000BA4                 LDRB            R3, [R0]
.text:00000BA6                 LDRB.W          LR, [R0,#(byte_40D1 - 0x40D0)]
.text:00000BAA                 STRB            R2, [R1,#(byte_40CB - 0x40CA)]
.text:00000BAC                 EOR.W           R2, R12, #0xFC
.text:00000BB0                 STRB            R2, [R1,#(byte_40CC - 0x40CA)]
.text:00000BB2                 EOR.W           R1, R3, #0x62
.text:00000BB6                 LDRB            R4, [R0,#(byte_40D2 - 0x40D0)]
.text:00000BB8                 LDRB            R2, [R0,#(word_40D6 - 0x40D0)]
.text:00000BBA                 LDRB            R6, [R0,#(byte_40D3 - 0x40D0)]
.text:00000BBC                 LDRB            R5, [R0,#(byte_40D4 - 0x40D0)]
.text:00000BBE                 EOR.W           R2, R2, #0x62
.text:00000BC2                 LDRB.W          R12, [R0,#(byte_40D5 - 0x40D0)]
.text:00000BC6                 STRB            R1, [R0]
.text:00000BC8                 EOR.W           R1, LR, #0x62
.text:00000BCC                 STRB            R1, [R0,#(byte_40D1 - 0x40D0)]
.text:00000BCE                 EOR.W           R1, R4, #0x62
.text:00000BD2                 STRB            R1, [R0,#(byte_40D2 - 0x40D0)]
.text:00000BD4                 EOR.W           R1, R6, #0x62
.text:00000BD8                 STRB            R1, [R0,#(byte_40D3 - 0x40D0)]
.text:00000BDA                 EOR.W           R1, R5, #0x62
.text:00000BDE                 STRB            R1, [R0,#(byte_40D4 - 0x40D0)]
.text:00000BE0                 EOR.W           R1, R12, #0x62
.text:00000BE4                 STRB            R1, [R0,#(byte_40D5 - 0x40D0)]
.text:00000BE6                 LDRB            R1, [R0,#(word_40D6+1 - 0x40D0)]
.text:00000BE8                 LDRB            R3, [R0,#(byte_40D8 - 0x40D0)]
.text:00000BEA                 EOR.W           R1, R1, #0x62
.text:00000BEE                 STRB            R2, [R0,#(word_40D6 - 0x40D0)]
.text:00000BF0                 STRB            R1, [R0,#(word_40D6+1 - 0x40D0)]
.text:00000BF2                 EOR.W           R1, R3, #0x62
.text:00000BF6                 STRB            R1, [R0,#(byte_40D8 - 0x40D0)]
.text:00000BF8                 LDRB            R1, [R0,#(byte_40D9 - 0x40D0)]
.text:00000BFA                 EOR.W           R1, R1, #0x62
.text:00000BFE                 STRB            R1, [R0,#(byte_40D9 - 0x40D0)]
.text:00000C00                 LDRB            R1, [R0,#(byte_40DA - 0x40D0)]
.text:00000C02                 EOR.W           R1, R1, #0x62
.text:00000C06                 STRB            R1, [R0,#(byte_40DA - 0x40D0)]
.text:00000C08                 LDRB            R1, [R0,#(byte_40DB - 0x40D0)]
.text:00000C0A                 EOR.W           R1, R1, #0x62
.text:00000C0E                 STRB            R1, [R0,#(byte_40DB - 0x40D0)]
.text:00000C10                 LDRB            R1, [R0,#(byte_40DC - 0x40D0)]
.text:00000C12                 EOR.W           R1, R1, #0x62
.text:00000C16                 STRB            R1, [R0,#(byte_40DC - 0x40D0)]
.text:00000C18                 LDRB            R1, [R0,#(byte_40DD - 0x40D0)]
.text:00000C1A                 EOR.W           R1, R1, #0x62
.text:00000C1E                 STRB            R1, [R0,#(byte_40DD - 0x40D0)]
.text:00000C20                 LDRB            R1, [R0,#(byte_40DE - 0x40D0)]
.text:00000C22                 EOR.W           R1, R1, #0x62
.text:00000C26                 STRB            R1, [R0,#(byte_40DE - 0x40D0)]
.text:00000C28                 LDRB            R1, [R0,#(byte_40DF - 0x40D0)]
.text:00000C2A                 EOR.W           R1, R1, #0x62
.text:00000C2E                 STRB            R1, [R0,#(byte_40DF - 0x40D0)]
.text:00000C30                 LDRB            R1, [R0,#(byte_40E0 - 0x40D0)]
.text:00000C32                 EOR.W           R1, R1, #0x62
.text:00000C36                 STRB            R1, [R0,#(byte_40E0 - 0x40D0)]
.text:00000C38                 LDRB            R1, [R0,#(byte_40E1 - 0x40D0)]
.text:00000C3A                 EOR.W           R1, R1, #0x62
.text:00000C3E                 STRB            R1, [R0,#(byte_40E1 - 0x40D0)]
.text:00000C40                 LDRB            R1, [R0,#(byte_40E2 - 0x40D0)]
.text:00000C42                 EOR.W           R1, R1, #0x62
.text:00000C46                 STRB            R1, [R0,#(byte_40E2 - 0x40D0)]
.text:00000C48                 LDRB            R1, [R0,#(byte_40E3 - 0x40D0)]
.text:00000C4A                 EOR.W           R1, R1, #0x62
.text:00000C4E                 STRB            R1, [R0,#(byte_40E3 - 0x40D0)]
.text:00000C50                 LDRB            R1, [R0,#(byte_40E4 - 0x40D0)]
.text:00000C52                 EOR.W           R1, R1, #0x62
.text:00000C56                 STRB            R1, [R0,#(byte_40E4 - 0x40D0)]
.text:00000C58                 LDRB            R1, [R0,#(byte_40E5 - 0x40D0)]
.text:00000C5A                 EOR.W           R1, R1, #0x62
.text:00000C5E                 STRB            R1, [R0,#(byte_40E5 - 0x40D0)]
.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函数。
[Asm] 纯文本查看 复制代码
.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, [SP,#0xC+var_10]!
.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, [R1] ; __stack_chk_guard
.text:00000ACE                 LDR             R1, [R4]
.text:00000AD0                 STR             R1, [SP,#0x18+var_14]
.text:00000AD2                 MOVS            R1, #0
.text:00000AD4                 STR             R1, [SP,#0x18+env]
.text:00000AD6                 LDR             R1, [R0]
.text:00000AD8                 LDR             R3, [R1,#0x18] ; 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, [SP,#0x18+var_14]
.text:00000AE6                 LDR             R2, [R4]
.text:00000AE8                 SUBS            R1, R2, R1
.text:00000AEA                 ITTT EQ
.text:00000AEC                 ADDEQ           SP, SP, #8
.text:00000AEE                 LDREQ.W         R8, [SP+0x10+var_10],#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, [SP,#0x18+env]
.text:00000AFA                 LDR             R0, =(off_4010 - 0xB02)
.text:00000AFC                 LDR             R2, [R5]
.text:00000AFE                 ADD             R0, PC  ; off_4010
.text:00000B00                 LDR             R1, [R0] ; byte_40A0 ; R1="android/support/v7/app/AppCompiatActivity"
.text:00000B02                 MOV             R0, R5  ; R0=env
.text:00000B04                 LDR             R2, [R2,#0x18] ; R2=FindClass
.text:00000B06                 BLX             R2
.text:00000B08                 MOV             R6, R0  ; R6=AppCompiatActivity_clazz
.text:00000B0A                 LDR             R0, [R5]
.text:00000B0C                 MOV             R1, R6  ; R1=AppCompiatActivity_clazz
.text:00000B0E                 LDR             R2, [R0,#0x54] ; 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, [R1]
.text:00000B1C                 BEQ             loc_AE0
.text:00000B1E                 LDR             R0, [R5]
.text:00000B20                 MOV             R1, R6  ; R1=AppCompiatActivity_clazz
.text:00000B22                 MOVS            R3, #1
.text:00000B24                 LDR.W           R12, [R0,#0x35C] ; 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。
[Asm] 纯文本查看 复制代码
.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"进行变换,算法如下:
[Plain Text] 纯文本查看 复制代码
表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,内容为:
[Plain Text] 纯文本查看 复制代码
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,算法如下:
[Plain Text] 纯文本查看 复制代码
for i = 0 to 255 do
       T[i] = K[i mod keylen];

临时向量T初始化后的结果为:
[Plain Text] 纯文本查看 复制代码
"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,算法如下:
[Plain Text] 纯文本查看 复制代码
j=0;
for i = 0 to 255 do
    j = (j + S[i] + T[i]) mod 256;
    swap(S[i], S[j]);

6. 接下来就是计算rc4密钥,对输入字符进行rc4加密+base64转码。
计算rc4密钥流的算法如下:
[Plain Text] 纯文本查看 复制代码
i, j = 0;
for r = 0 to len do  //len为明文长度
    i = (i + 1) mod 256;
    j = (j + S[i]) mod 256;
    swap(S[i], S[j]);
    t = (S[i] + S[j]) mod 256;
    k[r] = S[t];

base64原理:
[Plain Text] 纯文本查看 复制代码
base64(3个字节有24个bit,对应4个base64字符):
    M        a        n
01001101  01100001  01101110
{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的代码,里面写了详细的注释:
[Asm] 纯文本查看 复制代码
.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, [R1] ; __stack_chk_guard
.text:00000796                 STR             R1, [SP,#0x238+var_22C]
.text:00000798                 LDR             R1, [R1]
.text:0000079A                 STR             R1, [SP,#0x238+var_20]
.text:0000079C                 LDR             R1, [R0]
.text:0000079E                 LDR.W           R3, [R1,#0x2A4] ; R3=GetStringUTFChars
.text:000007A2                 MOV             R1, R2
.text:000007A4                 MOVS            R2, #0
.text:000007A6                 BLX             R3      ; 获取指向输入字符串的char*指针
.text:000007A8                 STR             R0, [SP,#0x238+INPUT]
.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] ; 通过一个小循环,去掉R1指向的字符串中的'-',
.text:000007F0                                         ; 得到"650f909c721736479331c82df8b98e98",保存到R8指向的内存中
.text:000007F2                 ADDS            R1, #1
.text:000007F4                 CMP             R3, #0x2D ; '-'
.text:000007F6                 ITT NE
.text:000007F8                 STRNEB.W        R3, [R8,R0]
.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, [R6,R0]
.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,R1] ; R8="650f909c721736479331c82df8b98e98"
.text:00000826                                         ; R1初始值为1fh,然后减1,也就是依次从此字符串由后向前取字符
.text:0000082A                 SUBS            R1, #1
.text:0000082C                 ADD.W           R3, R3, #0x40000000
.text:00000830                 STRB            R0, [R6,R4] ; 通过一个小循环,将最初的字符串("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] ; 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, [R5] ; 从表中取出转换后的字符
.text:0000086A
.text:0000086A loc_86A                                 ; CODE XREF: sub_784+DE↑j
.text:0000086A                 STRB.W          R5, [R3],#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 3C  25 6C 99 97 06 56 8F DE
.text:00000884                                         ; 40 11 64 07 36 15 70 CA  18 17 7D 6A DB 13 30 37
.text:00000884                                         ; 29 60 E1 23 28 8A 50 8C  AC 2F 88 20 27 0F 7C 52
.text:00000884                                         ; A2 AB FC A1 CC 21 14 1F  C2 B2 8B 2C B0 3A 66 46
.text:00000884                                         ; 3D BB 42 A5 0C 75 22 D8  C3 76 1E 83 74 F0 F6 1C
.text:00000884                                         ; 26 D1 4F 0B FF 4C 4D C1  87 03 5A EE A4 5D 9E F4
.text:00000884                                         ; C8 0D 62 63 3E 44 7B A3  68 32 1B AA 2D 05 F3 F7
.text:00000884                                         ; 16 61 94 E0 D0 D3 98 69  78 E9 0A 65 91 8E 35 85
.text:00000884                                         ; 7A 51 86 10 3F 7F 82 DD  B5 1A 95 E7 43 FD 9B 24
.text:00000884                                         ; 45 EF 92 5C E4 96 A9 9C  55 89 9A EA F9 90 5F B8
.text:00000884                                         ; 04 84 CF 67 93 00 A6 39  A8 4E 59 31 6B AD 5E 5B
.text:00000884                                         ; 77 B1 54 DC 38 41 B6 47  9F 73 BA F8 AE C4 BE 34
.text:00000884                                         ; 01 4B 2A 8D BD C5 C6 E8  AF C9 F5 CB FB CD 79 CE
.text:00000884                                         ; 12 71 D2 FA 09 D5 BC 58  19 80 DA 49 1D E6 2E E3
.text:00000884                                         ; 7E B7 3B B3 A0 B9 E5 57  6E D9 08 EB C7 ED 81 F1
.text:00000884                                         ; F2 BF C0 A7 4A D6 2B B4  72 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[i]=K[i mod keylen];
.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, [R11,R1] ; 这行指令中的R1,从0-23h,循环变换。
.text:00000894                                         ; 所以R1即上面算法中的“i mod 23h(keylen)”
.text:00000894                                         ; R11="36f36b3c-a03e-4996-8759-8408e626c215"
.text:00000898                 STRB            R0, [R4,R5] ; 临时向量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, [SP,#0x238+var_T]
.text:000008A6                 SUBS            R0, #0x29 ; ')'
.text:000008A8                 UXTB            R0, R0  ; R0=10
.text:000008AA                 LDRB.W          R1, [R9,R0] ; R9指向状态向量S,R1=S[10]
.text:000008AE                 STRB.W          R1, [SP,#0x238+var_S] ; S[0]=S[10]
.text:000008B2                 MOVS            R1, #0xD7 ; R1=0xD7
.text:000008B4                 STRB.W          R1, [R9,R0] ; S[10]=0xD7=S[0]
.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[i]+T[i]) mod 256;
.text:000008B8                                         ; (4)    swap(S[i],S[j]);
.text:000008BA
.text:000008BA loc_8BA                                 ; CODE XREF: sub_784+15E↓j
.text:000008BA                 LDRB.W          R2, [R9,R1] ; R2=S[i]:R9指向状态向量S,R1即上面算法中的i,初始值为1。
.text:000008BE                 LDRB            R3, [R4,R1] ; R3=T[i]:R4指向临时向量T
.text:000008C0                 ADD             R3, R2  ; R3=S[i]+T[i](对应上述算法中的第3行)
.text:000008C2                 ADD             R0, R3  ; R0=j+S[i]+T[i](对应上述算法中的第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[i]+T[i]) mod 256(对应上述算法中的第3行)
.text:000008D0                 LDRB.W          R3, [R9,R0] ; R3=S[j](对应上述算法中的第4行)
.text:000008D4                 STRB.W          R3, [R9,R1] ; S[i]=S[j](对应上述算法中的第4行)
.text:000008D8                 ADDS            R1, #1  ; i+=1
.text:000008DA                 CMP.W           R1, #0x100
.text:000008DE                 STRB.W          R2, [R9,R0] ; S[j]=S[i](对应上述算法中的第4行)
.text:000008E2                 BNE             loc_8BA
.text:000008E4                 LDR             R0, [SP,#0x238+INPUT] ; 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, [R11,#3] ; 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, [SP,#0x238+var_230]
.text:00000910                 UMULL.W         R0, R1, R0, R2
.text:00000914                 ADD.W           R0, R5, R1,LSR#2
.text:00000918                 STR             R0, [SP,#0x238+var_234]
.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, [SP,#0x238+var_228]
.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, [SP,#0x238+var_228] ; var_228保存的是一个偏移值,用于计算保存base64编码结果的最后一个字符的位置
.text:00000944                 UXTB.W          R6, R11 ; R11=明文字符的RC4加密结果,将其无符号扩展到32bit,赋值给R6
.text:00000948                 ADDS            R3, R1, R2 ; R2是明文字符索引
.text:0000094A                 LDRB            R4, [R0,R3] ; 取出之前保存的“索引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                                         ; 01001101  01100001  01101110
.text:00000950                                         ; {010011}{01 0110}{0001 01}{101110}
.text:00000950                                         ;   索引1   索引2     索引3   索引4
.text:00000950                                         ; ------------------------------------------------------
.text:00000950                                         ; 根据4个索引,去查base64字符表
.text:00000954                 LDRB            R4, [R1,R4] ; 查表,取出索引2对应的base64字符
.text:00000956                 STRB            R4, [R0,R3] ; 保存索引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, [R4,#1] ; 保存索引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, [SP,#0x238+var_228] ; 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, [SP,#0x238+var_228]
.text:0000098E                 LDRB            R6, [R0,R3] ; 取出之前保存的“索引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                                         ; 01001101  01100001  01101110
.text:00000990                                         ; {010011}{01 0110}{0001 01}{101110}
.text:00000990                                         ;   索引1   索引2     索引3   索引4
.text:00000990                                         ; ------------------------------------------------------
.text:00000990                                         ; 根据4个索引,去查base64字符表
.text:00000994                 LDRB            R6, [R1,R6] ; 查表,取出索引3对应的base64字符
.text:00000996                 EOR.W           R6, R6, #0xF ; 对于索引3对应的base64字符,还要再异或一下0xF
.text:0000099A                 STRB            R6, [R0,R3] ; 保存索引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, [R1,R6] ; R6是索引4,查表,取出索引4对应的base64字符
.text:000009A4                 STRB            R1, [R3,#1] ; 保存索引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[i]) mod 256;
.text:000009A8                                         ; (5)    swap(S[i],S[j]);
.text:000009A8                                         ; (6)    t=(S[i]+S[j]) mod 256;
.text:000009A8                                         ; (7)    k[r]=S[t];
.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,R10] ; R9指向状态向量S,取出S[R10](对应第4行中的S[i])
.text:000009C2                 ADD.W           R3, R12, R1 ; R12即如上产生密钥流算法中的j,即R3=j+S[i](对应第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[i]) mod 256(对应第4行)
.text:000009D6                 LDRB.W          R3, [R9,R12] ; R9指向状态向量S,从S中取出索引S[R12],即S[j](对应第5行)
.text:000009DA                 STRB.W          R3, [R9,R10] ; S[i]=S[j](对应第5行)
.text:000009DE                 STRB.W          R1, [R9,R12] ; S[j]=S[i](对应第5行)
.text:000009E2                 LDRB.W          R4, [R9,R10] ; R4=S[j](对应第6行)
.text:000009E6                 LDR             R3, [SP,#0x238+INPUT] ; R3指向明文字符串
.text:000009E8                 ADD             R1, R4  ; R1=S[i]+S[j](对应第6行)
.text:000009EA                 LDRB            R3, [R3,R2] ; 取出一个明文字符
.text:000009EC                 UXTB            R1, R1  ; 利用UXTB做mod256运算,即R1=(S[i]+S[j]) mod 256;(对应第6行)
.text:000009EE                 LDRB.W          R1, [R9,R1] ; R1=S[t],即取出密钥流中的一个密钥字节(对应第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                                         ; 01001101  01100001  01101110
.text:00000A14                                         ; {010011}{01 0110}{0001 01}{101110}
.text:00000A14                                         ;   索引1    索引2    索引3   索引4
.text:00000A14                                         ; ------------------------------------------------------
.text:00000A14                                         ; 根据4个索引,去查base64字符表
.text:00000A16                 LDR             R6, [SP,#0x238+var_228] ; var_228保存的是一个偏移值,用于计算保存base64编码结果的最后一个字符的位置
.text:00000A18                 ADD             R1, PC  ; byte_4050 ; R1="!:#$%&()+-*/`~_[]{}?<>,.@^abcdefghijklmnopqrstuvwxyz0123456789\';"
.text:00000A1A                 ADD             R6, R2  ; R2是明文字符索引
.text:00000A1C                 LDRB            R4, [R1,R4] ; 查表,取出索引1对应的base64字符
.text:00000A1E                 EOR.W           R4, R4, #7 ; 对于索引1对应的base64字符,还要再异或一下0x7
.text:00000A22                 STRB            R4, [R0,R6] ; 保存索引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, [R4,#1] ; 保存索引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, [R1,R3]
.text:00000A3E                 MOVW            R2, #0x3B3B ; 在最后补';;',相当于标准base64的'=='
.text:00000A3E                                         ; 因为最后一个base索引缺4bit,需要补两个'='
.text:00000A42                 STRH            R2, [R4,#2]
.text:00000A44
.text:00000A44 loc_A44                                 ; CODE XREF: sub_784+304↓j
.text:00000A44                 STRB            R1, [R4,#1] ; 保存最后一个base64字符
.text:00000A46
.text:00000A46 loc_A46                                 ; CODE XREF: sub_784+1A0↑j
.text:00000A46                                         ; sub_784+2B6↑j
.text:00000A46                 LDR             R1, [SP,#0x238+var_230]
.text:00000A48                 CBZ             R1, loc_A66
.text:00000A4A                 LDR             R2, =(a98gaLTnFjJG - 0xA54)
.text:00000A4C                 MOVS            R1, #1  ; R1=1
.text:00000A4E                 LDR             R4, [SP,#0x238+var_234]
.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, [R0,R5] ; 下面是一个循环,比较最后的base64字符串和" {9*8ga*l!Tn?@#fj'j$\\g;;"
.text:00000A54                 ADDS            R5, #1
.text:00000A56                 LDRB.W          R6, [R2],#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, [SP,#0x238+var_20] ; 后面是堆栈检查,不用看了
.text:00000A6A                 LDR             R2, [SP,#0x238+var_22C]
.text:00000A6C                 LDR             R2, [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, [R1,R3] ; 查表取出最后一个base64字符(最后一个base64索引可能不足6位)
.text:00000A84                 MOVS            R2, #0x34 ; '4'
.text:00000A86                 STRB            R2, [R4,#2] ; 在base64编码结果的最后加个'4'。
.text:00000A86                                         ; R4目前指向保存base64编码结果的倒数第2个字符位置
.text:00000A88                 B               loc_A44
.text:00000A88 ; End of function sub_784

把sub_784函数分析清楚之后,就可以写出破解脚本了:
[Python] 纯文本查看 复制代码
# 最后的结果是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[i] == ';':
        str_base64 += ';'
    elif i % 4 == 0:
        str_base64 += chr(ord(str_result[i]) ^ 0x7)
    elif i % 4 == 2:
        str_base64 += chr(ord(str_result[i]) ^ 0xf)
    else:
        str_base64 += str_result[i]
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[i % len(rc4_KEY)]
#print rc4_T

# 重新排列状态向量S
j = 0
for i in range(256):
    j = (j + rc4_S[i] + ord(rc4_T[i])) % 256
    rc4_S[i], rc4_S[j] = rc4_S[j], rc4_S[i]
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[i]) %256
    rc4_S[i], rc4_S[j] = rc4_S[j], rc4_S[i]
    t = (rc4_S[i] + rc4_S[j]) % 256;
    str_input += chr(ord(e) ^ rc4_S[t])
print 'str_input=' + str_input

运行得到:fu0kzHp2aqtZAuY6
文/十八垧

Transformers.rar

1.02 MB, 下载次数: 120, 下载积分: 吾爱币 -1 CB

免费评分

参与人数 45吾爱币 +38 热心值 +41 收起 理由
小学生啊 + 1 谢谢@Thanks!
chenjyuj + 1 + 1 用心讨论,共获提升!
HUAGEBIN + 1 + 1 谢谢@Thanks!
Tomcrack520 + 1 用心讨论,共获提升!
疯火戏猪猴 + 1 + 1 谢谢@Thanks!
墨瞳无泪心无殇 + 1 + 1 果然我连渣都算不上?
叶隽 + 1 我很赞同!
nauh + 1 我很赞同!
堂前燕 + 1 + 1 我很赞同!
baiafeu + 1 + 1 热心回复!
springkang + 1 + 1 我很赞同!
yanimals + 1 + 1 热心回复!
hjw45611 + 1 + 1 我很赞同!
Mr.Eleven + 1 谢谢@Thanks!
corvusg + 1 + 1 用心讨论,共获提升!
照片依旧 + 1 + 1 热心回复!
耳食之辈 + 1 热心回复!
liansen + 1 &amp;lt;font style=&amp;quot;vertical-align: inherit;&amp;quot;&amp;gt;&amp;lt;font style=
伞兵 + 1 + 1 用心讨论,共获提升!
Moyuan + 1 666
dralausky + 1 + 1 鼓励转贴优秀软件安全工具和文档!
z1234567890 + 1 感谢您的宝贵建议,我们会努力争取做得更好!
gaoyong0713 + 1 好东西,继续
Mr_Blake + 1 + 1 用心讨论,共获提升!
CCNA + 1 + 1 已经处理,感谢您对吾爱破解论坛的支持!
zhclwr + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
静叶流云 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
lemniscate + 1 + 1 谢谢@Thanks!
SwIIInG + 1 + 1 用心讨论,共获提升!
Lugia + 1 + 1 用心讨论,共获提升!
ggshihai + 1 + 1 热心回复!
soyiC + 1 + 1 用心讨论,共获提升!
yixi + 1 + 1 谢谢@Thanks!
笙若 + 1 + 1 谢谢@Thanks!
风骚的跑位 + 1 + 1 用心讨论,共获提升!
Populace + 1 + 1 热心回复!
l15828636136y + 1 + 1 用心讨论,共获提升!
SliverCrow + 1 + 1 用心讨论,共获提升!
yaoyao7 + 1 + 1 用心讨论,共获提升!
chly0828 + 1 + 1 我很赞同!
itmaple + 1 我很赞同!
FengziZhang + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
梦游枪手 + 2 + 1 用心讨论,共获提升!
hxw0204 + 1 + 1 谢谢@Thanks!
zctsir + 1 感谢您的宝贵建议,我们会努力争取做得更好!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
闲月疏云 发表于 2019-5-7 17:05
比较适合我这种逆向渣来练手
出类拔萃  Rank: 4
精华2
威望17 点

我差点信了你的鬼话.jpg

点评

楼主的.md。。。  发表于 2019-5-7 23:58
推荐
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么
3#
Loveherk 发表于 2019-5-7 15:06
我是不是第一个来看的,虽然啥也看不懂,大佬能不能给我推荐一下如果要学这东西的话,开端在哪
4#
loonglee 发表于 2019-5-7 15:13
欢迎分析讨论交流,吾爱破解论坛有你更精彩!
5#
_默默_ 发表于 2019-5-7 15:21
大哥  你这样做题一般得做多久,汇编一句句的的看也太难了吧
6#
AmIzero 发表于 2019-5-7 16:20
python大法好
7#
Pingerfy 发表于 2019-5-7 16:30
Loveherk 发表于 2019-5-7 15:06
我是不是第一个来看的,虽然啥也看不懂,大佬能不能给我推荐一下如果要学这东西的话,开端在哪

论坛有出过系列教程的 可以搜一下
8#
血色天空 发表于 2019-5-7 17:12
楼主厉害,我脑袋都看云了
9#
cat95f 发表于 2019-5-7 17:29
是编程吗?太难学
10#
Y阿奴 发表于 2019-5-7 17:33
看得懂代码,然并卵。。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-19 21:29

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表