2023XHLJ-RE

2023XHLJ-RE

😭 题目难度适中,着重是对技巧的考察,可惜手生了,有题浪费的时间比较久,赛时没能AK。

注: 部分知识点仅针对题目浅显学习,如有严重错误敬请师傅们指正,不剩感激。

Dual personality

core: 通过hook从32位切换到64位执行,期间穿插反调试代码。

hook切换函数

image-20230202224436717

获取调用该函数的返回地址,将该处7个字节的指令转存到va开辟的空间中,并在其中通过0xE9+偏移回到retaddr+size的地址继续执行。原本ret处的代码被修改为jmp 0x33切换64位模式,一共有两处调用,可在该函数下断点获取64位代码地址。

1
2
3
sub_401120(7u, (int)sub_4011D0) 
// "\xea\xd0\x11\x40\x00\x33\x00" -> jmp 0x33:0x4011d0
//jmp 0x33:0x401290

复制一份文件,将可选头的Magic选为PE64(0x20B),之后IDA64打开即可查看x4011d0和0x401290处的反汇编代码。

1
2
3
4
5
6
7
8
9
10
11
.text:00000000000011D0                 mov     rax, gs:60h
.text:00000000000011D9 mov al, [rax+2]
.text:00000000000011DC mov ds:40705Ch, al
.text:00000000000011E3 test al, al
.text:00000000000011E5 jnz short loc_11F5
.text:00000000000011E7 mov r12d, 5DF966AEh
.text:00000000000011ED mov ds:407058h, r12d
.text:00000000000011F5
.text:00000000000011F5 loc_11F5: ; CODE XREF: .text:00000000000011E5↑j
.text:00000000000011F5 mov eax, 407000h
.text:00000000000011FB jmp qword ptr [rax]

用过gs:60获取PEB,并通过+2查看BeingDebug,并将反调试标志存在0x40705C地址(可在原32位文件中查看该偏移处的变量),并将后续0x407058( dword_407058)的初始值设置为0x5DF966AEh,之后jmp到刚刚保存的现场,进而跳转到原retaddr+Size处执行。

image-20230202230446850

之后会调用0x40705c处代码处理数据,并使用了刚刚的反调试标志。

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
 mov     rbp, rsp
.text:0000000000001204 mov al, ds:40705Ch
.text:000000000000120D test al, al
.text:000000000000120F jz short loc_1245 ;anti-dbg
.text:0000000000001211 mov rax, [rbp+10h]
.text:0000000000001215 mov rbx, [rax]
.text:0000000000001218 rol rbx, 20h
.text:000000000000121C mov [rax], rbx
...
mov rax, [rbp+10h]
.text:0000000000001249 mov rbx, [rax]
.text:000000000000124C rol rbx, 0Ch
.text:0000000000001250 mov [rax], rbx
.text:0000000000001253 mov rbx, [rax+8]
.text:0000000000001257 rol rbx, 22h
.text:000000000000125B mov [rax+8], rbx
.text:000000000000125F mov rbx, [rax+10h]
.text:0000000000001263 rol rbx, 38h
.text:0000000000001267 mov [rax+10h], rbx
.text:000000000000126B mov rbx, [rax+18h]
.text:000000000000126F rol rbx, 0Eh
.text:0000000000001273 mov [rax+18h], rbx
.text:0000000000001277 mov ebx, 0
.text:000000000000127C
.text:000000000000127C loc_127C: ; CODE XREF: .text:0000000000001243↑j
.text:000000000000127C mov ebx, 0
.text:0000000000001281 xor rax, rax
.text:0000000000001284 mov rsp, rbp
.text:0000000000001287 pop rbp
.text:0000000000001288 retf 8

偏移0x1290处的代码负责修改最后异或的数据,可通过调试获取异或值,并设置了check出的指令地址0x4014C5,数据均可调试32位程序获取,断点不能打在64位模式的代码,并且注意前两处处理的反调试。

exp

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
def hex_dump(x):
for i in x:
print("0x"+hex(i)[2:].zfill(8),end=' ')
print()

def ror(x,n):
return ((x>>n) | (x<<(64-n)&0xffffffffffffffff))&0xffffffffffffffff
kk=0x4a827704
cc=[0xE20F4FAA, 0x549941E4, 0x7E842B2C, 0x788B8FBC, 0x5E8873D3, 0x708547AE, 0xCE09B331, 0xCA0DF513]
for i in range(8):
cc[i]^=kk
sk=[0xc,0x22,0x38,0xe]
x=0x5DF966AE-0x21524111
for i in range(0,8,2):
tmp=(cc[i+1]<<32 | cc[i])
tmp=ror(tmp,sk[i//2])
cc[i]=tmp&0xffffffff
cc[i+1]=tmp>>32

for i in range(8):
tmp=cc[i]
cc[i]=(cc[i]-x+0x100000000)%0x100000000
x^=tmp
for i in cc:
print(int.to_bytes(i,4,'little').decode(),end='')

BabyRe

core: init函数和atexit函数

initterm中依次执行如下函数。

image-20230202232731003

顺序如下

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
void *__thiscall sub_401170(void *this)
{
char v2; // [esp+0h] [ebp-E4h]
size_t i; // [esp+D0h] [ebp-14h]

__CheckForDebuggerJustMyCode(byte_4090A2);
sub_4025A0("Input:", v2);
sub_402620("%99s", (char)mystr);
for ( i = 0; i < strlen(mystr); ++i )
{
if ( mystr[i] < '0' || mystr[i] > '9' ) // 0-9
ExitProcess(0);
}
return this;
}
//atexit注册了最终check函数sub_4014E0

void *__thiscall sub_401230(void *this)
{
int i; // [esp+D0h] [ebp-14h]

__CheckForDebuggerJustMyCode(&byte_4090A2);
for ( i = 0; i < 8; ++i )
data_tb[i] = ~data_tb[i];
return this;
}
//atexit注册了sub_4015C0用于第二步加密

//sub_4012B0用于hook main函数中调用的GetLastError函数 hook_func为0x4019D0 修改了sha1的加密常量
//atexit注册了sub_401670用于第一步加密

atexit函数的调用顺序为栈式,即后注册先调用,所以数据处理流程是sub_401670->sub_4014E0->sub_4014E0。

第一步是base8编码,3byte扩充为8byte,表为01234567,并且check了加密后的enc[16:112]字节即36字节的输入,加密后的前16字节参与sub_4014E0的魔改sha1运算,最后取输入的最后6个字节用RC4加密enc[:112],根据第一步的check可求中间的36字节,根据最后一步rc4解密需要爆破后6字节,如果第一步解密的字节在rc4解密的明文中那么也可获取前6个字节。

exp

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
from Crypto.Util.number import *
from tqdm import tqdm

def Rc4_Encrypt(m,key):
s=[]
t=[]
out=[] #putput
for i in range(256):
s.append(i)
t.append(ord(key[i%len(key)]))

j=0
for i in range(256):
j=(j+s[i]+t[i])%256
s[i],s[j]=s[j],s[i]

i,j=0,0
for p in range(len(m)):
i=(i+1)%256
j=(j+s[i])%256

s[i],s[j]=s[j],s[i]

index=(s[i]+s[j])%256
out.append(s[index]^m[p])
return out

if __name__ == '__main__':

t=[0x3F, 0x95, 0xBB, 0xF2, 0x57, 0xF1, 0x7A, 0x5A, 0x22, 0x61, 0x51, 0x43, 0xA2, 0xFA, 0x9B, 0x6F, 0x44, 0x63, 0xC0, 0x08, 0x12, 0x65, 0x5C, 0x8A, 0x8C, 0x4C, 0xED, 0x5E, 0xCA, 0x76, 0xB9, 0x85, 0xAF, 0x05, 0x38, 0xED, 0x42, 0x3E, 0x42, 0xDF, 0x5D, 0xBE, 0x05, 0x8B, 0x35, 0x6D, 0xF3, 0x1C, 0xCF, 0xF8, 0x6A, 0x73, 0x25, 0xE4, 0xB7, 0xB9, 0x36, 0xFB, 0x02, 0x11, 0xA0, 0xF0, 0x57, 0xAB, 0x21, 0xC6, 0xC7, 0x46, 0x99, 0xBD, 0x1E, 0x61, 0x5E, 0xEE, 0x55, 0x18, 0xEE, 0x03, 0x29, 0x84, 0x7F, 0x94, 0x5F, 0xB4, 0x6A, 0x29, 0xD8, 0x6C, 0xE4, 0xC0, 0x9D, 0x6B, 0xCC, 0xD5, 0x94, 0x5C, 0xDD, 0xCC, 0xD5, 0x3D, 0xC0, 0xEF, 0x0C, 0x29, 0xE5, 0xB0, 0x93, 0xF1, 0xB3, 0xDE, 0xB0, 0x70]
c1=b'162304651523346214431471150310701503207116032063140334661543446114434066142304661563446615430464'
# for i in tqdm(range(1000000)):
# key=str(i).zfill(6)
# ans=Rc4_Encrypt(t,key)
# if c1 in bytes(ans):
# print(key)
key='807391'
s=bytes(Rc4_Encrypt(t,key)).decode()
num = 0
for i in range(len(s)):
num += int(s[i]) * pow(8, len(s) - 1 - i)
print(long_to_bytes(num))
flag='561516915572239428449843076691286116796614807391'

注: 此处是和群友交流后的思路,赛时对前6个字节单独爆破求解,因为不愿copy伪码修正代码,考虑到前6个字节的秘钥空间比较小,并且过了第二个check到最后一步rc4如果验证成功会有输出,所以可以patch最后的jz为jmp让其只要过了第二步check就会有输出,之后结合subprocess直接爆破即可。

1
2
3
4
5
6
7
8
9
10
import subprocess
from tqdm import tqdm
if __name__ == "__main__":
for i in tqdm(range(1000000)):
nows=str(i).zfill(6)
p = subprocess.Popen("./BabyRE_2.exe", stdin=subprocess.PIPE, stdout=subprocess.PIPE)
s = nows + "915572239428449843076691286116796614" + '\n'
out, err = p.communicate(bytes(s.encode()))
if b'DASCTF{' in out:
print('yes',nows)

程序运算比较复杂,1个多小时才爆出结果。

Berkeley

core: ebpf程序,使用bpftool提取字节码,存在源码注释。

类似题目有去年虎符fype,ebpf字节码逆向方面syj师傅写过详细的总结->传送门

程序没有去符号,通过搜索Berkeley_bpf__create_skeleton函数可快速定位到bpf字节码所在地。

image-20230203190848335

字节码文件在.rodata段,大小0x2118,用过idapy脚本dump即可,之后可用llvm-objdumpidaghidra的插件来识别字节码文件。

效果ghidra算是不错的,但是一些变量偏移不明确,读起来也十分痛苦,ghidra反编译的LBB01。

image-20230203191956793

所以这里推荐bpftool工具导出的ir,即使没有源码注释也可以修改后重编译再用ida查看,流程如下。

首先bpf程序需要一些内存操作权限,在开启linux_server时要以root权限运行,并运行过bpf_open_and_load将字节码载入内存。

image-20230203192612066

之后新开的终端运行bpftool prog show,获取载入内核后的函数id为38和40。

image-20230203192822558

之后运行bpftool prog dump xlated id 38提取LBB0_1处的ir。

image-20230203193004373

可见包括**;源码**的注释,根据存在的源码注释即可快速理解代码,对于LBB0_2则采用同样的方法。

RE群友: strings即可dump出源码,用ghidra看老久真是输麻了。

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
k=[0xC1, 0xD1, 0x02, 0x61, 0xD6, 0xF7, 0x13, 0xA2, 0x9B, 0x20, 0xD0, 0x4A, 0x8F, 0x7F, 0xEE, 0xB9, 0x00, 0x63, 0x34, 0xB0, 0x33, 0xB7, 0x8A, 0x8B, 0x94, 0x60, 0x2E, 0x8E, 0x21, 0xFF, 0x90, 0x82, 0xD5, 0x87, 0x96, 0x78, 0x22, 0xB6, 0x48, 0x6C, 0x45, 0xC7, 0x5A, 0x16, 0x80, 0xFD, 0xE4, 0x8C, 0xBF, 0x01, 0x1F, 0x4B, 0x79, 0x24, 0xA0, 0xB4, 0x23, 0x4D, 0x3B, 0xC5, 0x5D, 0x6F, 0x0D, 0xC9, 0xD4, 0xCA, 0x55, 0xE0, 0x39, 0xAD, 0x2B, 0xCD, 0x2C, 0xEC, 0xC2, 0x6B, 0x30, 0xE6, 0x0C, 0xA8, 0x9A, 0x2F, 0xF6, 0xE8, 0xBB, 0x32, 0x57, 0xFB, 0x0B, 0x9D, 0xF2, 0x3F, 0xB5, 0xF9, 0x59, 0xE5, 0x10, 0xCF, 0x51, 0x41, 0xE9, 0x50, 0xDF, 0x26, 0x74, 0x58, 0xCB, 0x64, 0x54, 0x73, 0xAB, 0xF4, 0xB2, 0x9F, 0x18, 0xF8, 0x4E, 0xFE, 0x08, 0x1D, 0x4F, 0x49, 0xD3, 0xAC, 0x38, 0x12, 0x77, 0x11, 0x69, 0x07, 0x1C, 0x99, 0xB3, 0xE7, 0x3D, 0x05, 0xD8, 0xFC, 0x70, 0x46, 0x93, 0x09, 0x65, 0x89, 0xB1, 0xC6, 0x52, 0xFA, 0xD2, 0x0E, 0xA9, 0x17, 0xE3, 0x91, 0xA1, 0x68, 0x5B, 0x2A, 0xF0, 0xC3, 0x42, 0xCC, 0x29, 0xDE, 0xDC, 0x85, 0x98, 0x31, 0x5C, 0xBC, 0x2D, 0xEF, 0x5E, 0x7E, 0xAF, 0x67, 0x62, 0xA7, 0x56, 0x88, 0xA4, 0x43, 0x40, 0xE1, 0x37, 0x9E, 0x36, 0x76, 0x71, 0x84, 0xBD, 0x06, 0x8D, 0x47, 0x7D, 0x53, 0xD7, 0xC8, 0xCE, 0x15, 0x92, 0x95, 0x4C, 0x28, 0x6D, 0x75, 0xEB, 0x7C, 0xF3, 0xBE, 0xAA, 0xB8, 0xED, 0x03, 0x3C, 0x27, 0x3E, 0x19, 0xDD, 0xA6, 0x66, 0x25, 0x1E, 0xC4, 0x6E, 0xC0, 0xE2, 0xDB, 0x3A, 0xD9, 0x81, 0xA5, 0x1B, 0xF5, 0x04, 0xAE, 0xBA, 0xEA, 0x97, 0x83, 0x35, 0x44, 0xA3, 0x7A, 0x1A, 0xF1, 0x86, 0xDA, 0x7B, 0x14, 0x72, 0x9C, 0x6A, 0x0F, 0x5F, 0x0A, 0x00]
c=[0xF3, 0x27, 0x47, 0x1B, 0x8F, 0x09, 0xFB, 0x17, 0x70, 0x48, 0xB0, 0x53, 0x32, 0xDB, 0xC0, 0xB8, 0x63, 0x2D, 0x40, 0x4B, 0xF5, 0x16, 0xF0, 0x35, 0xE7, 0xDF, 0xEA, 0xA2, 0x9C, 0x41, 0xB3, 0x25, 0xD7, 0x0C, 0x33, 0x9C, 0x7B, 0x5A, 0xCD, 0x13, 0xBB, 0xEE, 0x3E, 0x0E, 0xF2, 0xCF, 0x35, 0xDA, 0xAF, 0xA2, 0x66, 0x7D, 0x38, 0x37, 0x67, 0x1E, 0x1F, 0x6B, 0x7B, 0x30, 0x0B, 0x7A, 0x02, 0xA9, 0xC8, 0x61, 0x27, 0x41, 0xDB, 0x01, 0x22, 0x31, 0x6F, 0xB6, 0xD4, 0x1B, 0x04, 0xD3, 0x94, 0xB8, 0x46, 0xC7, 0x24, 0xCF, 0xBD, 0xAF, 0x0B, 0xDC, 0x2E, 0xBB, 0xB2, 0x71, 0xF4, 0x99, 0x57, 0x36, 0xD1, 0x95, 0x52, 0x92, 0xBA, 0x6D, 0xF3, 0x30, 0x50, 0x59, 0x9B, 0xEA, 0x2F, 0x83, 0xDC, 0xF0, 0xDE, 0x57, 0xA1, 0xAC, 0xD2, 0x51, 0xA2, 0x1D, 0x59, 0xA8, 0x00, 0xB6, 0xE2, 0x65, 0x41, 0x0C, 0x4F, 0xEB, 0xF0, 0x2E, 0x58, 0x2A, 0x1F, 0xF4, 0x95, 0x72, 0x88, 0x7C, 0xA9, 0x0E, 0xCB, 0x3C, 0x42, 0xB9, 0xF3, 0x49, 0x9B, 0x52, 0x98, 0x12, 0xA3, 0x17, 0x51, 0xC0, 0x59, 0x40, 0x0A, 0xBC, 0xE8, 0x4C, 0x04, 0xFB, 0x13, 0x0A, 0x17, 0x3F, 0xE6, 0x36, 0x97, 0xDF, 0xB3, 0xE2, 0x42, 0x7F, 0xF8, 0xCC, 0x0E, 0xD1, 0x77, 0xC4, 0xA8, 0x46, 0x48, 0xE3, 0xF1, 0x0A, 0xEF, 0x94, 0x56, 0x54, 0x5B, 0xCA, 0xBD, 0xDD, 0x7F, 0x56, 0x47, 0xC2, 0x99, 0xFA, 0x89, 0xCC, 0xE1, 0xB9, 0x3A, 0x78, 0xE2, 0x37, 0x58, 0x01, 0x1B, 0xC3, 0x4B, 0xE6, 0x8C, 0xF3, 0xE5, 0xB6, 0x71, 0x9E, 0x63, 0xAF, 0x11, 0xCE, 0x87, 0xF6, 0x6E, 0xDE, 0xC8, 0xB1, 0xD0, 0x7A, 0x15, 0x6C, 0x10, 0x08, 0x99, 0x7B, 0x22, 0x55, 0x10, 0x7A, 0x82, 0x73, 0xFC, 0x62, 0xCB, 0x34, 0xA7, 0xB7, 0x62, 0xFA, 0x6B, 0x9F]

out=[0]*256
"""
output[i] = key[output[i] ^ key[i]];
"""
for i in range(256):
out[i]=k[i]^k.index(c[i])
out[i]=k.index(out[i])^0xff

arr=[0x20, 0x95, 0x20, 0x95, 0x80, 0xAA, 0xFF, 0xC0, 0x4A, 0xAE, 0x8A, 0x5C, 0x0D, 0x8D, 0x1F, 0x6D, 0x0D, 0x8D, 0xA2, 0x15, 0xEE, 0xF3, 0x4D, 0xC8, 0x7F, 0x75, 0x23, 0xCE, 0xD1, 0x50, 0xC1, 0xDF]
"""
unsigned char uc1 = flag[i/8];
unsigned char uc2 = ~(flag[i/8] + arr[i%8]);
output[i] = key[uc1 ^ uc2];
"""
#爆破arr
# for a in range(32,127):
# for b in range(32,127):
# for c in range(32,127):
# ans0=[]
# for i in range(8):
# t=out[i]^a
# t=(t-a+0x100)%0x100
# ans0.append(t)
# ans1=[]
# for i in range(8):
# t=out[i+8]^b
# t=(t-b+0x100)%0x100
# ans1.append(t)
# ans2=[]
# for i in range(8):
# t = out[i + 16] ^ c
# t = (t - c + 0x100) % 0x100
# ans2.append(t)
# if ans0==ans1 and ans2==ans1:
# print(ans0)
# print(chr(a),chr(b),chr(c))
"""
[128, 64, 32, 16, 8, 4, 2, 3]
[128, 64, 32, 16, 8, 4, 2, 1]
"""
t=[128, 64, 32, 16, 8, 4, 2, 1]
for i in range(0,256,8):
for k in b'0123456789abcdef': #爆破flag
for p in range(8):
if(k^(k+t[p]))&0xff != out[i+p]:
break
else:
print(chr(k),end='')

EasyVT

core: 驱动程序用于处理用户程序中的VT-exit异常,了解vt的无条件退出指令和相关常量即可解题。

VT学习资源参考: 传送门

VT相关常量定义在vtsystem.h中,驱动中相关常量可以在其中搜索来理解相关含义。

驱动入口出调用sub_4026C0函数,之后是sub_402240,其中一条指令非常关键,设置了host程序的ip为处理函数。

1
2
HOST_RIP                        = 0x00006c16,
sub_4010BF(0x6C16, (int)sub_401C10);

sub_401C10函数保存寄存器上下文,并调用sub_401C90函数,进入关键的异常处理模块。比对常量表可得知case对应哪种退出原因,并且皆为无条件退出指令的处理。

image-20230203194712187

查看应用程序main函数的汇编,包括4步循环,每个循环主要由三个动作,第一个是将输入每次取连续8字节分别放到esi和edi,第二个是vm指令跑出异常,第三步进行check。

image-20230203194932981

根据其抛出的异常顺序,从vmxon开始到vmxoff结束,依次查看其对应的异常处理函数即为加密逻辑,这和普通驱动逆向的功能码差不多,比较障眼法的是对rc4的key、魔改tea的sum和delta有多次赋值,只要按照正常的调用流程查看异常函数依次覆盖即可。

完整的流程就不再赘述了,这里提出几点需要注意的。

vmcall的异常处理函数的if分支是停止驱动时服务才会走,为DriverUnload的处理。

image-20230203195536556

vmxoff是对rc4和tea加密结果的比对,并赋值eax,也就是用户程序最后通过eax的值来check。

image-20230203195840157

简述加密逻辑是: rc4加密按照EDI ESI顺序,Tea加密是按照ESI EDI的顺序,在VMPTRST指令的处理中交换了顺序。

解密魔改tea

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
#include<iostream>
#include<Windows.h>
using namespace std;
void encrypt(unsigned int*m,unsigned int*k) {
unsigned int v0 = m[0];
unsigned int v1 = m[1];
unsigned int delta = 0xAB95D3CC;
unsigned int sum = 0x20000000;
for (int i = 0; i < 0x20; i++) {
v0 -= (k[2] + (v1 >> 5)) ^ (sum + v1) ^ (k[3] + (v1 << 4));
v1+= (k[0] + (v0 >> 5)) ^ (sum + v0) ^ (k[1] + (v0 << 4));
sum -= delta;
}
printf("0x%08x\n", sum);
m[0] = v0;
m[1] = v1;
}
void decrypt(unsigned int* enc, unsigned int* k) {
unsigned int v0 = enc[0];
unsigned int v1 = enc[1];
unsigned int sum = 0x20000000;
unsigned int delta = 0xC95D6ABF;
for (int i = 0; i < 0x20; i++) sum -= delta;

for (int i = 0; i < 0x20; i++) {
sum += delta;
v1 -= (k[0] + (v0 >> 5)) ^ (sum + v0) ^ (k[1] + (16*v0 ));
v0 += (k[2] + (v1 >> 5)) ^ (sum + v1) ^ (k[3] + (16*v1));
}
enc[0] = v0;
enc[1] = v1;
}
int main() {
unsigned int enc[8] = {0x5C073994, 0x0D805CB3, 0x87DDA586, 0x0317FB8E, 0x6520EF29, 0x5A4987AF, 0xEB2DC2A4, 0x38CF470E};
unsigned int key[4] = { 0x102030,0x8090A0B0,0x0C0D0E0F0 ,0x40506070 };

for (int i = 0; i < 8; i += 2) {
decrypt(enc + i, key);
for (int j = 0; j < 4; j++)
printf("%d,", *((unsigned char*)(enc + i + 1) + j));
for (int j = 0; j < 4; j++)
printf("%d,", *((unsigned char*)(enc + i ) + j));
}

return 0;
}

解密rc4

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
def Rc4_Encrypt(m,key):
s=[]
t=[]
out=[] #putput
for i in range(256):
s.append(i)
t.append(ord(key[i%len(key)]))

j=0
for i in range(256):
j=(j+s[i]+t[i])%256
s[i],s[j]=s[j],s[i]

i,j=0,0
for p in range(len(m)):
i=(i+1)%256
j=(j+s[i])%256

s[i],s[j]=s[j],s[i]

index=(s[i]+s[j])%256
out.append(s[index]^m[p])
return out

if __name__ == '__main__':
#0 2 3 1
delta=0xC95D6ABF
sum=0x20000000
k='04e52c7e31022b0b'
d=[213,18,156,184,44,122,126,177,209,66,152,191,33,115,37,230,208,69,205,237,33,41,38,178,220,73,155,185,44,45,114,186]
for i in range(0,len(d),8):
ans=Rc4_Encrypt(bytearray(d[i:i+8]),k)
ans=bytes(ans).decode()
print(ans[4:8]+ans[:4],end='')

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!