pollux's Dairy

汇编分析一个so文件中的变形RC4和变形base64算法

字数统计: 4.5k阅读时长: 28 min
2020/01/04 Share

Prolong

1
2
3
4
5
6
7
8
9
.init_array:00003E78 ; ELF Initialization Function Table
.init_array:00003E78 ; ===========================================================================
.init_array:00003E78
.init_array:00003E78 ; Segment type: Pure data
.init_array:00003E78 AREA .init_array, DATA
.init_array:00003E78 ; ORG 0x3E78
.init_array:00003E78 DCD .datadiv_decode5009363700628197108+1
.init_array:00003E78 ; .init_array ends
.init_array:00003E78

程序在.init_array中重新初始化了一些字段,包括生成RC4的初始密钥K、状态向量S,下面说下K的生成过程:
1) so中原始存储了长度为36数据:
0x93,0x90,0x95,0xC3,0x9C,0x95,0x9C,0xC6,0x88,0x92,0x97,0x94,
0x92,0x88,0x96,0x93,0x91,0x92,0x88,0x9C,0x96,0x96,0x94,0x88
0xC6,0x9D,0x97,0xC1,0xC3,0x9D,0xC7,0x9C,0x9D,0xC0,0x9C,0x9D
2) 经过.init_array重新初始化变成了:
650f909c-7217-3647-9331-c82df8b98e98
3) 经过一系列移位变成了:
89e89b8f-d28c-1339-7463-7127c909f056
4) 然后经过一个映射表abcdef0123456789=>dbeafc2409715836
映射为了最终的K36f36b3c-a03e-4996-8759-8408e626c215

状态向量也进行了重新初始化,下面主要分析:
1、变形的RC4算法
2、变形的base64算法
3、给出解密脚本

一、变形的RC4算法

RC4包含两个向量,状态向量S[256],向量T[256],T是由用户自定义初始密钥K轮转填充到256字节,算法主要包含两部分内容
1、用T置乱重排S
2、用T和明文生成密文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
状态向量S:
uint8_t S[256] = {
0xD7,0xDF, 2,0xD4,0xFE,0x6F,0x53,0x3C,0x25,0x6C,0x99,0x97, 6,0x56,0x8F,0xDE,//; 0
0x40,0x11,0x64, 7,0x36,0x15,0x70,0xCA,0x18,0x17,0x7D,0x6A,0xDB,0x13,0x30,0x37,//; 16
0x29,0x60,0xE1,0x23,0x28,0x8A,0x50,0x8C,0xAC,0x2F,0x88,0x20,0x27, 0xF,0x7C,0x52,//; 32
0xA2,0xAB,0xFC,0xA1,0xCC,0x21,0x14,0x1F,0xC2,0xB2,0x8B,0x2C,0xB0,0x3A,0x66,0x46,//; 48
0x3D,0xBB,0x42,0xA5, 0xC,0x75,0x22,0xD8,0xC3,0x76,0x1E,0x83,0x74,0xF0,0xF6,0x1C,//; 64
0x26,0xD1,0x4F, 0xB,0xFF,0x4C,0x4D,0xC1,0x87, 3,0x5A,0xEE,0xA4,0x5D,0x9E,0xF4,//; 80
0xC8, 0xD,0x62,0x63,0x3E,0x44,0x7B,0xA3,0x68,0x32,0x1B,0xAA,0x2D, 5,0xF3,0xF7,//; 96
0x16,0x61,0x94,0xE0,0xD0,0xD3,0x98,0x69,0x78,0xE9, 0xA,0x65,0x91,0x8E,0x35,0x85,//; 112
0x7A,0x51,0x86,0x10,0x3F,0x7F,0x82,0xDD,0xB5,0x1A,0x95,0xE7,0x43,0xFD,0x9B,0x24,//; 128
0x45,0xEF,0x92,0x5C,0xE4,0x96,0xA9,0x9C,0x55,0x89,0x9A,0xEA,0xF9,0x90,0x5F,0xB8,//; 144
4,0x84,0xCF,0x67,0x93, 0,0xA6,0x39,0xA8,0x4E,0x59,0x31,0x6B,0xAD,0x5E,0x5B,//; 160
0x77,0xB1,0x54,0xDC,0x38,0x41,0xB6,0x47,0x9F,0x73,0xBA,0xF8,0xAE,0xC4,0xBE,0x34,//; 176
1,0x4B,0x2A,0x8D,0xBD,0xC5,0xC6,0xE8,0xAF,0xC9,0xF5,0xCB,0xFB,0xCD,0x79,0xCE,//; 192
0x12,0x71,0xD2,0xFA, 9,0xD5,0xBC,0x58,0x19,0x80,0xDA,0x49,0x1D,0xE6,0x2E,0xE3,//; 208
0x7E,0xB7,0x3B,0xB3,0xA0,0xB9,0xE5,0x57,0x6E,0xD9, 8,0xEB,0xC7,0xED,0x81,0xF1,//; 224
0xF2,0xBF,0xC0,0xA7,0x4A,0xD6,0x2B,0xB4,0x72,0x9D, 0xE,0x6D,0xEC,0x48,0xE2,0x33,//;
}
初始密钥K = 36f36b3c-a03e-4996-8759-8408e626c215

1、用T置乱重排S

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.text:B3E408BA loc_B3E408BA                            ; CODE XREF: sub_B3E40784+15E↓j
.text:B3E408BA LDRB.W R2, [R9,R1] ; S[i], R9是状态向量S的地址 ,R1是相当于算法中的i
.text:B3E408BE LDRB R3, [R4,R1] ; T[i], R4是向量T的地址
.text:B3E408C0 ADD R3, R2 ; T[i] + S[i]
.text:B3E408C2 ADD R0, R3 ; j + T[i] + S[i] ,R0相当于算法中的j
.text:B3E408C4 ASRS R3, R0, #0x1F
.text:B3E408C6 ADD.W R3, R0, R3,LSR#24
.text:B3E408CA BIC.W R3, R3, #0xFF
.text:B3E408CE SUBS R0, R0, R3 ; R0 = R0 % 256
.text:B3E408D0 LDRB.W R3, [R9,R0] ; R3 = S[j]
.text:B3E408D4 STRB.W R3, [R9,R1] ; S[i] = R3
.text:B3E408D8 ADDS R1, #1
.text:B3E408DA CMP.W R1, #0x100
.text:B3E408DE STRB.W R2, [R9,R0] ; S[j] = R2, R2即为原R[i], swap完成
.text:B3E408E2 BNE loc_B3E408BA ; 循环

翻译成C语言算法如下:

1
2
3
4
5
6
7
i = 0;
j = T[0] - 0x29; //j = 10
swap(S[i],S[j]); //swap(S[0],S[10])
for(i = 1;i<256;i++){
j = (j + T[i] + S[i]) % 256;
swap(S[i],S[j]);
}

T[0] - 0x29就是(T[0] + S[0])256,优化一下就是:

1
2
3
4
5
j = 0;
for(i = 0;i<256;i++){
j = (j + T[i] + S[i]) % 256;
swap(S[i],S[j]);
}

2、用状态向量T和明文一次一密生成密文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
.text:B3E409A8 loc_B3E409A8                            ; CODE XREF: sub_B3E40784+1B0↑j
.text:B3E409A8 ; sub_B3E40784+2B4↓j
.text:B3E409A8 ADD.W R1, R10, #1 ; R10=算法中的i
.text:B3E409AC CMP R2, #0
.text:B3E409AE MOV.W R3, R1,ASR#31
.text:B3E409B2 ADD.W R3, R1, R3,LSR#24
.text:B3E409B6 BIC.W R3, R3, #0xFF ; 将R3低8位清零,0xff = 255
.text:B3E409BA SUB.W R10, R1, R3 ; 上面计算了R10 = (R10+1)%256
.text:B3E409BE LDRB.W R1, [R9,R10] ; R1 = S[R10],R9 = 状态向量S的地址
.text:B3E409C2 ADD.W R3, R12, R1 ; R12=算法中的j
.text:B3E409C6 MOV.W R4, R3,ASR#31
.text:B3E409CA ADD.W R4, R3, R4,LSR#24
.text:B3E409CE BIC.W R4, R4, #0xFF
.text:B3E409D2 SUB.W R12, R3, R4 ; 上面计算了R12 = (R12+R1)%256
.text:B3E409D6 LDRB.W R3, [R9,R12] ; 开始对S数组swap
.text:B3E409DA STRB.W R3, [R9,R10] ; S[i] = S[j]
.text:B3E409DE STRB.W R1, [R9,R12] ; S[j] = 原s[i]
.text:B3E409E2 LDRB.W R4, [R9,R10] ; R4 = swap后的S[i]
.text:B3E409E6 LDR R3, [SP,#0x238+s] ; R3 = 明文地址
.text:B3E409E8 ADD R1, R4 ; R1是原S[i]
.text:B3E409EA LDRB R3, [R3,R2] ; R3 = s[R2],取待加密明文字符
.text:B3E409EC UXTB R1, R1 ; 高24位清零,相当于模256
.text:B3E409EE LDRB.W R1, [R9,R1] ; R1 = S[ (S[i] + S[j]) % 256 ]
.text:B3E409F2 EOR.W R11, R1, R3 ; 异或,RC4结果保存在R11
.text:B3E409F6 BEQ loc_B3E40A0E ; 若字符索引index=0,则开始处理第一个字符

RC4部分对应的C语言算法如下:

1
2
3
4
5
6
7
i = (i + 1)%256;
m = S[i];
j = (j + S[i])%256;
S[i] = S[j];
S[j] = m;
n = S[i];
C = S[ (m+n) % 256 ] ^ s[index];

3、变形的RC4算法总结

从上面分析,可以知道该算法与常规RC4算法的不同:
1、使用自定义的初始密钥K
2、使用自定义的状态向量S


二、变形的base64算法

base64算法中,3个字符为一组被编码成4个base64字符,假设待编码字符索引为index,某一组的三个字符为x0、x1、x2,该组base64编码结果对应的字符为y0、y1、y2、y3。

这里需要判断当前处理的index是这一组中的第几个字符,条件为:

1
2
.text:B3E409AC CMP             R2, #0
.text:B3E409F6 BEQ loc_B3E40A0E
1
2
3
4
5
6
7
.text:B3E409F8 MOV             R1, #0xAAAAAAAB
.text:B3E40A00 UMULL.W R1, R3, R2, R1
.text:B3E40A04 LSRS R1, R3, #1 ; 计算结果:R1 = R2 / 3
.text:B3E40A06 ADD.W LR, R1, R1,LSL#1 ; LR = R1 + R1*2 即LR = 3*(R2/3)
.text:B3E40A0A CMP LR, R2
.text:B3E40A0C BNE loc_B3E40936 ; 若index!=0 && index%3!=0
.text:B3E40A0E loc_B3E40A0E

上面为两个条件,整合到一起就是

1
2
3
4
if(index!=0 && 3*(index/3)!=index)
goto loc_B3E40936;
else
goto loc_B3E40A0E;

这里就判断了当前index,处于小组的位置,是不是x0,若是x0,就去执行loc_B3E40A0E;若是x1、x2就去执行loc_B3E40936

但是执行loc_B3E40936后,还需要判断当前index处于的位置是x1还是x2,就有了下面的判断

1
2
3
4
5
6
7
.text:B3E40936 CMP             R2, #1                  ; 比较index和1
.text:B3E40938 ITT NE ; 不相等执行第1、2条指令
.text:B3E4093A ADDNE.W R1, LR, #1 ; R2!=1, Then R1 = LR + 1
.text:B3E4093E CMPNE R1, R2
.text:B415E940 BNE loc_B415E96A ; 不相等,说明index处于x2的位置,跳转loc_B3E4096A
.text:B415E942 ...
.text:B415E944...
1
2
3
if(3*(index/3)+1 != index)
goto loc_B3E4096A;
...

若3*(index/3)+1 != index,则说明当前index处于x2的位置,否则说明当前index处于x1的位置

1、处理第1个字符,得到第1个base64字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.text:B3E40A0E loc_B3E40A0E                            ; 开始处理x0
.text:B3E40A0E LDR R1, =(byte_B3E44050 - 0xB3E40A1C) ; R1 = base64字符表地址相对PC的差值
.text:B3E40A10 UXTB.W R3, R11 ; 将x0低8位,无符号扩展到32位,即高24位清零,保存到R3
.text:B3E40A14 LSRS R4, R3, #2 ; 逻辑右移2位,取高6位
.text:B3E40A16 LDR R6, [SP,#0x238+var_228] ; R6 = N,这里N是K[3] = 0x33
.text:B3E40A18 ADD R1, PC ; byte_B3E44050 ; R1=base64字符表地址
.text:B3E40A1A ADD R6, R2 ; R6 = N + index,R2是字符索引index
.text:B3E40A1C LDRB R4, [R1,R4] ; 取出第一个索引对应的base64字符,设为y0'
.text:B3E40A1E EOR.W R4, R4, #7 ; y0 = y0' ^ 7
.text:B3E40A22 STRB R4, [R0,R6] ; 保存第一个base64字符y0,R0为malloc的buf地址
.text:B3E40A24 ADDS R4, R0, R6 ; 取buf[N + index]的地址
.text:B3E40A26 MOVS R6, #0x30 ; '0'
.text:B3E40A28 AND.W R3, R6, R3,LSL#4 ; R3 = (R3<<4)& 00110000b
.text:B3E40A28 ; 即取x0低2位值
.text:B3E40A2C ADDS R6, R2, #1 ; index++
.text:B3E40A2E STRB R3, [R4,#1] ; 在buf[N + index + 1]写入x0低2位,将作为第二个base64字符y1的索引的高2位
.text:B3E40A30 CMP R6, R8 ; 判断明文字符索引index+1是否大于等于明文字符长度
.text:B3E40A30 ; 若相等,接下来就处理最后一个明文字符
.text:B3E40A32 BCS loc_B3E40A3C ; 若无符号index > len(s),则跳转,处理最后一个字符
.text:B3E40A34
.text:B3E40A34 loc_B3E40A34 ; 否则
.text:B3E40A34 ADDS R2, #1
.text:B3E40A36 CMP R2, R8
.text:B3E40A38 BCC loc_B3E409A8 ; 若index<=len(s),跳转loc_B3E409A8,继续计算下一个base64字符

初始密钥 K = 36f36b3c-a03e-4996-8759-8408e626c215

该部分算法总结:
1、取RC4加密结果C的低8位,然后取该值的高6位作为base64字符表索引
2、根据字符索引,查字符表,得到第一个base64字符,设为y0’
3、y0 = y0’ ^ 7
4、N = K[3]
5、将b写入buf[ N + index ]
6、将低2位写入buf[ N + index +1 ]
这里比常规的base64编码算法多了第三步

指令总结:
1、UXTB指令,无符号扩展到32位,即高24位清零 http://www.keil.com/support/man/docs/armasm/armasm_dom1361289924987.htm
2、取一个字符A的低2位,将其作为下一个字符索引的高2位,保存到B中 B = (A<<4) & 00110000b
3、CMP R1,R2 BCS label,无符号R1<R2,则跳转label
4、CMP R1,R2 BCC label,无符号R1>=R2,则跳转label

1
2
3
4
5
6
7
8
9
10
11
12
13
else
{
v26[v44 + v29] = byte_4050[(unsigned int)v36 >> 2] ^ 7;// 右移两位,得到第一个base64字符索引
v17 = (unsigned int)&v26[v44 + v29];
v27 = 16 * v36 & 0x30; // 获取索引2的高2位
*(_BYTE *)(v17 + 1) = v27; // v26[v44 + v29 +1] = 16 * v36 & 0x30
if ( v29 + 1 >= v24 )
{
v38 = byte_4050[v27];
*(_WORD *)(v17 + 2) = 0x3B3B;
goto LABEL_43;
}
}

2、处理第2个字符,得到第2个base64字符

下面是处理x1的过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
.text:B3E40936 loc_B3E40936                            ; CODE XREF: sub_B3E40784+288↓j
.text:B3E40936 CMP R2, #1 ; 比较index和1
.text:B3E40938 ITT NE ; 不相等执行第1、2条指令
.text:B3E4093A ADDNE.W R1, LR, #1 ; R2!=1, Then R1 = LR + 1
.text:B3E4093E CMPNE R1, R2
.text:B3E40940 BNE loc_B3E4096A
.text:B3E40942 LDR R1, [SP,#0x238+var_228] ; R1 = N
.text:B3E40944 UXTB.W R6, R11 ; R11=x1无符号扩展到32 位(高24位清0
.text:B3E40948 ADDS R3, R1, R2 ; R3 = N + index
.text:B3E4094A LDRB R4, [R0,R3] ; 取第二个base64字符,真正保存的是x0低2位
.text:B3E4094A ; R0为malloc的buf地址
.text:B3E4094C LDR R1, =(byte_B3E44050 - 0xB3E40952)
.text:B3E4094E ADD R1, PC ; byte_B3E44050 ; R1为base64字符表地址
.text:B3E40950 ORR.W R4, R4, R6,LSR#4 ; 1、取x1高4位
.text:B3E40950 ; 2、取x0低2位和上面数值进行与操作,得到一个新的6位值,作为第二个索引
.text:B3E40954 LDRB R4, [R1,R4] ; 查表,取第二个索引值对应的base64字符
.text:B3E40956 STRB R4, [R0,R3] ; 保存结果到buf[N + index]
.text:B3E40958 ADDS R4, R0, R3 ; R4 = buf[N + index]的地址
.text:B3E4095A MOVS R3, #0x3C ; '<' ; R3 = 00111100b
.text:B3E4095C AND.W R3, R3, R6,LSL#2 ; 将x1逻辑左移2位&00111100b
.text:B3E4095C ; 将x1低四位,后面作为第3个base64字符索引的高四位
.text:B3E40960 ADDS R6, R2, #1 ; index++
.text:B3E40962 CMP R6, R8
.text:B3E40964 STRB R3, [R4,#1] ; 将y2索引的高四位写入buf[N + index + 1]
.text:B3E40966 BCC loc_B3E40A34 ; 若R6<=R8,即index + 1 < len(s),跳转loc_B3E40A34,继续计算x2
.text:B3E40968 B loc_B3E40A82 ; index + 1 < len(s),当前index为最后一个字符,处理后续base64字符

该部分算法总结:
1、取x0低2位与x2的高4位,组成新的6位数值,作为base64字符表索引
2、根据字符索引,查字符表,得到第二个base64字符,设为y1
3、N = K[3]
4、将y1写入buf[ N + index ]
5、将x1低4位写入buf[ N + index +1 ]

指令总结:

1、IT(If-Then)指令:

1
2
3
4
5
.text:B3E40936 loc_B3E40936                            ; CODE XREF: sub_B3E40784+288↓j
.text:B3E40936 CMP R2, #1 ; 比较index和1
.text:B3E40938 ITT NE ; 不相等执行第1、2条指令
.text:B3E4093A ADDNE.W R1, LR, #1 ; R2!=1, Then R1 = LR + 1
.text:B3E4093E CMPNE R1, R2

IT指令用于根据特定条件来执行紧随其后的1~4条指令,其格式为:IT{x{y{z}}} {cond} 。其中x、y、z分别是执行第二、三、四条指令的条件,可取的值为T(then)或E(else),若为T,则执行cond对应的指令;若为E,则执行cond相反条件的指令。而cond对应执行第一条指令的条件。参考

2、 BCC

1
2
CMP A,B
BCC labal

A<B,则跳转到label

3、处理第3个字符,得到第3、4个base64字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.text:B415E96A loc_B415E96A                            ; CODE XREF: sub_B415E784+1BC↑j
.text:B415E96A CMP R2, #2
.text:B415E96C ITT NE
.text:B415E96E ADDNE.W R1, LR, #2
.text:B415E972 CMPNE R1, R2
.text:B415E974 BNE loc_B415EA34
.text:B415E976 LDR R1, =(byte_B4162050 - 0xB415E984)
.text:B415E978 AND.W R4, R11, #0xC0 ; 取x2的高2位,与x1的低4位可以组成一个6位base64字符索引
.text:B415E97C LDR.W LR, [SP,#0x238+var_228] ; LR = N
.text:B415E980 ADD R1, PC ; byte_B4162050 ; R1是base64字符表地址
.text:B415E982 ADD.W R3, LR, R2 ; R3 = N + index
.text:B415E986 ADD.W LR, LR, #1 ; LR++
.text:B415E98A STR.W LR, [SP,#0x238+var_228] ; N++
.text:B415E98E LDRB R6, [R0,R3] ; R0为buf的地址,取出x1的低四位
.text:B415E990 ORR.W R6, R6, R4,LSR#6 ; 组成新的6位base64字符索引
.text:B415E994 LDRB R6, [R1,R6] ; 查表,取出base64字符
.text:B415E996 EOR.W R6, R6, #0xF ; 取出的base64字符异或0xF
.text:B415E99A STRB R6, [R0,R3] ; 写入buf
.text:B415E99C AND.W R6, R11, #0x3F ; 取x2低6位
.text:B415E9A0 ADD R3, R0 ; 取当前buf地址
.text:B415E9A2 LDRB R1, [R1,R6] ; 根据x2的低6位,查表,取第4个base64字符
.text:B415E9A4 STRB R1, [R3,#1] ; 写入buf的下一个字节
.text:B415E9A6 B loc_B415EA34

这里再次判断了index在组的位置(感觉是多余的
根据注释可以清楚的看到,生成了第3、4个base64字符,其中和常规base64算法不同的是,第3个base64字符与0xF进行了异或处理

到此第一组3个字符,生成了4个base64字符。

4、strlen(s) % 3 = 1时的处理

当base64处理的字符串长度不能被3整除,会有其他的处理

常规的base64算法的处理方式是直接补零查表

而这个变形的base64算法有点不同

我们从当剩余字符为x0时的处理方式开始分析,从上面的跳转分析,可以知道该段代码在loc_00000A3C

1
2
3
4
5
6
7
.text:B4052A3C loc_B4052A3C                            ; CODE XREF: sub_B4052784+2AE↑j
.text:B4052A3C LDRB R1, [R1,R3] ; R1 = base64字符表,将x0的低2位左移4位,当做base64字符表索引,得到y1
.text:B4052A3E MOVW R2, #0x3B3B
.text:B4052A42 STRH R2, [R4,#2] ; R4为buf地址,y2=y3=0x3b
.text:B4052A44
.text:B4052A44 loc_B4052A44 ; CODE XREF: sub_B4052784+304↓j
.text:B4052A44 STRB R1, [R4,#1] ; 写入y1

用常规base64算法生成y0、y1后,不同的是,该变形算法在后面追加了0x3B3B,为“;;”,想当于base64算法中的==

5、strlen(s) % 3 = 2时的处理

当剩余字符为x1时的处理方式的分析,从上面的跳转分析,可以知道该段代码在loc_00000A82

1
2
3
4
5
6
7
8
.text:B3A1EA82 loc_B3A1EA82                            
.text:B3A1EA82 LDRB R1, [R1,R3] ; R1为base64字符表,R3位x1低4位再左移2位的值,即y2的base64字符索引
.text:B3A1EA84 MOVS R2, #0x34 ; '4'
.text:B3A1EA86 STRB R2, [R4,#2] ; y3 = 0x34
.text:B3A1EA88 B loc_B3A1EA44

.text:B4052A44 loc_B4052A44
.text:B4052A44 STRB R1, [R4,#1] ; 写入y2

用常规base64算法生成y0、y1、y2后,不同的是,该变形算法在后面追加了0x34

至此变形base64算法分析完成

6、变形base64算法总结

设一组待编码的字符长度为L,生成编码字符为y0、y1、y2、y3

与传统base64算法不同的是:
1、字符表变成 !:#$%&()+-*/`~_[]{}?<>,.@^abcdefghijklmnopqrstuvwxyz0123456789\‘;”
2、y0 = y0 ^ 0x7
3、y2 = y2 ^ 0xF
4、若L % 3 = 2,y3 = 0x34

三、解密代码

最后处理的结果会与 {9*8ga*l!Tn?@#fj'j",0x24,"\g;; 对比

由以上分析,我们就可以写出解密代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import string
import binascii
RC4_key = "36f36b3c-a03e-4996-8759-8408e626c215"
base64_encoded = " {9*8ga*l!Tn?@#fj'j$\\g;;"
base64_table = "!:#$%&()+-*/`~_[]{}?<>,.@^abcdefghijklmnopqrstuvwxyz0123456789\\';";
base64_table_ori = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

RC4_S = [0xD7,0xDF, 2,0xD4,0xFE,0x6F,0x53,0x3C,0x25,0x6C,0x99,0x97, 6,0x56,0x8F,0xDE,
0x40,0x11,0x64, 7,0x36,0x15,0x70,0xCA,0x18,0x17,0x7D,0x6A,0xDB,0x13,0x30,0x37,
0x29,0x60,0xE1,0x23,0x28,0x8A,0x50,0x8C,0xAC,0x2F,0x88,0x20,0x27, 0xF,0x7C,0x52,
0xA2,0xAB,0xFC,0xA1,0xCC,0x21,0x14,0x1F,0xC2,0xB2,0x8B,0x2C,0xB0,0x3A,0x66,0x46,
0x3D,0xBB,0x42,0xA5, 0xC,0x75,0x22,0xD8,0xC3,0x76,0x1E,0x83,0x74,0xF0,0xF6,0x1C,
0x26,0xD1,0x4F, 0xB,0xFF,0x4C,0x4D,0xC1,0x87, 3,0x5A,0xEE,0xA4,0x5D,0x9E,0xF4,
0xC8, 0xD,0x62,0x63,0x3E,0x44,0x7B,0xA3,0x68,0x32,0x1B,0xAA,0x2D, 5,0xF3,0xF7,
0x16,0x61,0x94,0xE0,0xD0,0xD3,0x98,0x69,0x78,0xE9, 0xA,0x65,0x91,0x8E,0x35,0x85,
0x7A,0x51,0x86,0x10,0x3F,0x7F,0x82,0xDD,0xB5,0x1A,0x95,0xE7,0x43,0xFD,0x9B,0x24,
0x45,0xEF,0x92,0x5C,0xE4,0x96,0xA9,0x9C,0x55,0x89,0x9A,0xEA,0xF9,0x90,0x5F,0xB8,
4,0x84,0xCF,0x67,0x93, 0,0xA6,0x39,0xA8,0x4E,0x59,0x31,0x6B,0xAD,0x5E,0x5B,
0x77,0xB1,0x54,0xDC,0x38,0x41,0xB6,0x47,0x9F,0x73,0xBA,0xF8,0xAE,0xC4,0xBE,0x34,
1,0x4B,0x2A,0x8D,0xBD,0xC5,0xC6,0xE8,0xAF,0xC9,0xF5,0xCB,0xFB,0xCD,0x79,0xCE,
0x12,0x71,0xD2,0xFA, 9,0xD5,0xBC,0x58,0x19,0x80,0xDA,0x49,0x1D,0xE6,0x2E,0xE3,
0x7E,0xB7,0x3B,0xB3,0xA0,0xB9,0xE5,0x57,0x6E,0xD9, 8,0xEB,0xC7,0xED,0x81,0xF1,
0xF2,0xBF,0xC0,0xA7,0x4A,0xD6,0x2B,0xB4,0x72,0x9D, 0xE,0x6D,0xEC,0x48,0xE2,0x33,
]
RC4_T = []
t = ""
tmp = ""
for i in range(len(base64_encoded)):
if base64_encoded[i]==";":
t = base64_encoded[i]
tmp +=t
continue
if i%4==0:
t = chr(ord(base64_encoded[i])^0x7)
elif i%4 == 2:
t = chr(ord(base64_encoded[i])^0xF)
else:
t = base64_encoded[i]
tmp +=t
#print tmp#'{6*?gn*k![n8@,fm'e$[g;;

transtable = string.maketrans(base64_table,base64_table_ori)
transtmp = tmp.translate(transtable)
#print transtmp#/R6KTgnKkAPn8YWfm/eDPg==

base64_decoded = transtmp.decode('base64')
cipher = []
for i in range(len(base64_decoded)):
cipher.append(int(binascii.b2a_hex(base64_decoded[i]),16))

#生成T
for i in range(256):
RC4_T.append(ord(RC4_key[i%len(RC4_key)]))

#用T置乱S
j = RC4_T[0] - 0x29
RC4_S[0],RC4_S[j] = RC4_S[j],RC4_S[0]

for i in range(1,256):
j = (j + RC4_T[i] + RC4_S[i]) % 256
RC4_S[i],RC4_S[j] = RC4_S[j],RC4_S[i]

i = 0
j = 0
res = ""
for k in range(len(cipher)):
i = (i+1)%256
m = RC4_S[i]
j = (j + m)%256
RC4_S[i],RC4_S[j] = RC4_S[j],RC4_S[i]
n = RC4_S[i]
p = RC4_S[(m+n)%256] ^ cipher[k]
res += chr(p)
print res
CATALOG
  1. 1. Prolong
  2. 2. 一、变形的RC4算法
    1. 2.1. 1、用T置乱重排S
    2. 2.2. 2、用状态向量T和明文一次一密生成密文
    3. 2.3. 3、变形的RC4算法总结
  3. 3. 二、变形的base64算法
    1. 3.1. 1、处理第1个字符,得到第1个base64字符
    2. 3.2. 2、处理第2个字符,得到第2个base64字符
    3. 3.3. 3、处理第3个字符,得到第3、4个base64字符
    4. 3.4. 4、strlen(s) % 3 = 1时的处理
    5. 3.5. 5、strlen(s) % 3 = 2时的处理
    6. 3.6. 6、变形base64算法总结
  4. 4. 三、解密代码