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
文/十八垧 比较适合我这种逆向渣来练手
出类拔萃Rank: 4
精华2
威望17 点
我差点信了你的鬼话.jpg 还有一个问题:
.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么 我是不是第一个来看的,虽然啥也看不懂,大佬能不能给我推荐一下如果要学这东西的话,开端在哪 欢迎分析讨论交流,吾爱破解论坛有你更精彩! 大哥你这样做题一般得做多久,汇编一句句的的看也太难了吧 python大法好 Loveherk 发表于 2019-5-7 15:06
我是不是第一个来看的,虽然啥也看不懂,大佬能不能给我推荐一下如果要学这东西的话,开端在哪
论坛有出过系列教程的 可以搜一下 楼主厉害,我脑袋都看云了 是编程吗?太难学 看得懂代码,然并卵。。