day1
eare
custom_md5_init(seed);会检测断点,我们可以在输入和比较的数据下硬件断点,用写内存的方法把密文写回内存就可以在s1中看到flag。\n
密文:5C 76 4A 78 15 62 05 7C 6B 21 40 66 5B 1A 48 7A\n
1E 46 7F 28 02 75 68 2A 34 0C 4B 1D 3D 2E 6B 7A
17 45 07 75 47 27 39 78 61 0B
ko0h
前面的flag是假的,修一下jzjnz的花指令,可以看到主逻辑
魔改RC4
密文在sub_402A70()里,”DDDDAAAASSSS”
脚本如下
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//s 表的长度取 256
#define size 256
unsigned char sbox[257] = { 0 };
// 初始化 s 表
void init_sbox(unsigned char* key) {
unsigned int i, j, k;
int tmp;
for (i = 0; i < size; i++) {
sbox[i] = i;
}
j =k = 0;
for (i = 0; i < size; i++) {
tmp = sbox[i];
j = (j + tmp + key[i % strlen((char*)key)]) % size; //注意此处的长度,自己计算一下密钥和数据的长度多次尝试
sbox[i] = sbox[j];
sbox[j] = tmp;
/*if (++k >= 12)
k = 0;*/
}
}
// 加解密函数
void enc_dec(unsigned char* key, unsigned char* data) {
int i, j, k, R, tmp;
init_sbox(key);
j = k = 0;
for (i = 0; i < strlen((char*)data); i++) {
j = (j + 1) % size;
k = (k + sbox[j]) % size;
tmp = sbox[j];
sbox[j] = sbox[k];
sbox[k] = tmp;
R = sbox[(sbox[j] + sbox[k]) % size];
data[i] += R;
}
}
int main() {
unsigned char key[100] = "DDDDAAAASSSS";
unsigned char data[100] = { 24,-100,71,61,59,-31,41,39,-97,52,-125,-43,-19,-75,110,89,127,-34,71,-41,101,63,122,51,91,100,-74,-6,-108,85,-121,66,32,6,12,105,-2,114,-87,-28,-47,124 };
enc_dec(key, data);
printf("dec: %s\n", data);
return 0;
}
day3
oooooore
全是花指令,大概分为两种,jzjnz和callret,用脚本去花(脚本1),去除花指令后可以看到main中的加密逻辑,看字符串表可以看到一个rc4密钥,还可以定位到输入的位置。
mecpcy那里是密文,s是我们的输入。往下看我们的输入被传入了两个函数中,这应该就是加密函数了。第一个进去就是我们在字符串表看到的那个RC4。
在第二个函数中我们可以在流程图中看到一些常数,按r可以看到他们的字符串”expand 32-byte k”,这个明显就是salsa20或者chacha20加密了,和RC4差不多本质就是一个异或,可以用写内存的方法解决。(其实这些找不到也没什么大问题,下面的动调可以解决一切)
回到main函数,我们在输入的数据下硬件断点,输入一个正确长度的值进行动调,查看我们值的变化。这里我输入flag{aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa},继续运行,同时看我们输入数据的变化。
第一次改变在这里,有一个异或,发现数据来源于byte ptr [rcx+rdx]和[rbp-70h],我们在00005555555593BF下断点就可以看到byte ptr [rcx+rdx]是我们的输入,[rbp-70h]是一个地址,指向的地址里面只有一个数据,我们给这个数据下硬件断点继续溯源(其实可以不用再溯源了,这里是为了深入了解)
这次断在这个位置,上面的[rcx]是我们追踪的值,这个值来自byte ptr [rcx+rdx],不过好像被覆盖了,我们下断点查看。里面就是一串表(有点像main函数里面第二个函数上面那些数据),下面还有RC4的密钥,但是不确定是哪个加密函数。取消全部的断点,只保留我们输入数据的硬件断点,继续运行。
最后变化在这个位置,往前看看就能看到只有一个异或,还有一个RC4的盒,那么前面那个就是chacha20或者salsa20。(我们只需要知道加密只有两个异或就行)
再进行一次动调,这次我们把我们把密文作为输入写内存,并在最后一个数据下硬件断点。运行到最后一步加密,再次查看就可以看到flag
81 ED 7E 2F 93 B6 6F 8D 43 E5 C9 11 A9 F4 2B DB
AD CB 45 66 FA DF A9 61 28 65 31 D7 80 D5 18 FE
25 6E 94 05 83 51 B5 42 D2 9D
脚本1(去花)
import idautils
import idc
import idaapi
def nop_jzjnz(start_addr,endaddr,pattern):
length =len(pattern)
flag = 0
while start_addr < endaddr:
getbytes =idc.get_bytes(start_addr,length) #获取指定范围内指定地址的字节码并返回成列表
if(getbytes[0]==pattern[0] and getbytes[3]==pattern[3] and getbytes[6] == pattern[6] ): #匹配花指令模板
flag = 1
for i in range(length):
idc.patch_byte(start_addr + i,0x90) #nop
print(f"success! nop 0x{hex(start_addr)} to 0x{hex(start_addr + length -1)} length:{length}")
start_addr += length - 1
start_addr += 1
if(flag == 0):
print("Not find!!!")
def nop_range(start_addr,end_addr):
while(start_addr <= end_addr):
idc.patch_byte(start_addr,0x90)
start_addr += 1
print(f"success! nop 0x{start_addr} to 0x{end_addr}")
def remount():
try:
addr = idc.get_screen_ea()
func = idaapi.get_func(addr)
func_start = func.start_ea
idaapi.del_func(func_start)
idaapi.add_func(func_start)
print(f"success!! remount the func in 0X{func}")
except Exception as a:
print("some errors occur, remount falrue")
print(f"error : {a}")
start_addr = 0x0001000
end_addr = 0x07378
pattern_callret = [0xE8, 0x00, 0x00, 0x00, 0x00, 0x48, 0x83, 0x04, 0x24, 0x08, 0xC3, 0xE8, 0x90, 0x90, 0x90]
pattern_jzjnz3 = [0x0F, 0x85, 0x06, 0x00, 0x00, 0x00, 0x0F, 0x84, 0x01, 0x00, 0x00, 0x00, 0x21]
nop_jzjnz(start_addr,end_addr,pattern_jzjnz3)
nop_jzjnz(start_addr,end_addr,pattern_callret)
easyasm
sub_102C0
seg002:0000 sub_102C0 proc near ; CODE XREF: start+F↓p
seg002:0000 push ax
seg002:0001 push bx
seg002:0002 push cx
seg002:0003 push si
seg002:0004
seg002:0004 loc_102C4: ; CODE XREF: sub_102C0+29↓j
seg002:0004 mov bx, 1 ;设置标志默认为1,用于判断是否产生交换
seg002:0007 mov cx, ds:0 ;设置循环次数为cx为一个地址ds:0,loop默认cx统计次数
seg002:000B dec cx ;cx减一
seg002:000C lea si, ds:2 ;加载ds:2的地址到si
seg002:0010
seg002:0010 loc_102D0: ; CODE XREF: sub_102C0+22↓j
seg002:0010 mov ax, [si]
seg002:0012 cmp ax, [si+2] ;比较[si]和[si+2],即2字节组合比较
seg002:0015 jbe short loc_102DF ;若[si]<[si+2],跳转
seg002:0017 xchg ax, [si+2] ;交换
seg002:001A mov [si], ax
seg002:001C mov bx, 0 ;设置bx为0记录产生交换
seg002:001F
seg002:001F loc_102DF: ; CODE XREF: sub_102C0+15↑j
seg002:001F add si, 2
seg002:0022 loop loc_102D0 ;cx != 0时跳转,遍历数据
seg002:0024 cmp bx, 1 ;bx为1表示未产生交换,排序完毕
seg002:0027 jz short loc_102EB ;排序完毕
seg002:0029 jmp short loc_102C4 ;继续排序
seg002:002B ; ---------------------------------------------------------------------------
seg002:002B
seg002:002B loc_102EB: ; CODE XREF: sub_102C0+27↑j
seg002:002B pop si
seg002:002C pop cx
seg002:002D pop bx
seg002:002E pop ax
seg002:002F retn
seg002:002F sub_102C0 endp
seg002:002F
start
seg002:004C public start
seg002:004C start proc near
seg002:004C mov ax, seg seg000
seg002:004F mov ss, ax
seg002:0051 mov sp, 200h
seg002:0054 mov ax, seg seg001
seg002:0057 mov ds, ax
seg002:0059 assume ds:seg001
seg002:0059 mov es, ax
seg002:005B assume es:seg001
seg002:005B call sub_102C0 ;调用排序
seg002:005E mov dx, 0B2h ;输入存储位置,前两个字节存储数据的属性,所以数据从B4h开始
seg002:0061 mov ah, 0Ah
seg002:0063 int 21h ;阻断程序,用于输入 ; DOS - BUFFERED KEYBOARD INPUT
seg002:0063 ; DS:DX -> buffer
seg002:0065 mov bl, byte ptr aWelcomeToChunq+5Dh ; ""
seg002:0069 mov byte ptr [bx+0B4h], 24h ; '$'
seg002:006E mov cx, word ptr byte_10200 ;21
seg002:0072 add cx, cx ;42
seg002:0074 mov bx, 0 ;偏移量
seg002:0077
seg002:0077 loc_10337: ; CODE XREF: start+3C↓j
seg002:0077 mov al, [bx+0B4h] ;输入的数据
seg002:007B mov ah, [bx+2] ;ds:(bx+2) 指向的数据(这里是单字节)
seg002:007F xor al, ah ;两者异或
seg002:0081 mov [bx+0B4h], al ;修改输入数据
seg002:0085 add bx, 1 ;计数器(偏移量)加一
seg002:0088 loop loc_10337 ;cx 不为0时继续异或,cx会被减一
seg002:008A lea di, word_102B4 ;加载输入
seg002:008E lea si, byte_1022C ;加载密文
seg002:0092 call sub_102F0 ;比较函数
seg002:0095 jnz short loc_1035A ;根据返回判断结果,错误
seg002:0097 jmp short loc_10364 ;正确
seg002:0097 ; ---------------------------------------------------------------------------
seg002:0099 align 2
seg002:009A
seg002:009A loc_1035A: ; CODE XREF: start+49↑j
seg002:009A mov dx, 71h ; 'q'
seg002:009D mov ah, 9
seg002:009F int 21h ; DOS - PRINT STRING
seg002:009F ; DS:DX -> string terminated by "$"
seg002:00A1 jmp short loc_1036E
seg002:00A1 ; ---------------------------------------------------------------------------
seg002:00A3 align 2
seg002:00A4
seg002:00A4 loc_10364: ; CODE XREF: start+4B↑j
seg002:00A4 mov dx, 9Bh
seg002:00A7 mov ah, 9
seg002:00A9 int 21h ; DOS - PRINT STRING
seg002:00A9 ; DS:DX -> string terminated by "$"
seg002:00AB jmp short loc_1036E
seg002:00AB ; ---------------------------------------------------------------------------
seg002:00AD align 2
seg002:00AE
seg002:00AE loc_1036E: ; CODE XREF: start+55↑j
seg002:00AE ; start+5F↑j
seg002:00AE mov dx, 57h ; 'W'
seg002:00B1 mov ah, 9
seg002:00B3 int 21h ; DOS - PRINT STRING
seg002:00B3 ; DS:DX -> string terminated by "$"
seg002:00B5 mov ax, 4C00h
seg002:00B8 int 21h ; DOS - 2+ - QUIT WITH EXIT CODE (EXIT)
seg002:00B8 start endp ; AL = exit code
seg002:00B8
seg002:00B8 seg002 ends
seg002:00B8
seg002:00B8
seg002:00B8 end start
解密脚本
data = [
0x2030, 0x3040, 0x4050, 0x1022, 0x2011, 0x1666, 0x1522, 0x8899,
0x4155, 0x4044, 0x4288, 0x3321, 0x6033, 0xFFFF, 0x2221, 0x3366,
0x222C, 0x2CCC, 0x22CC, 0xCC22, 0xC2C2
]
box = [
0x44, 0x7C, 0x43, 0x72, 0x1D, 0x72, 0x74, 0x41, 0x05, 0x14, 0x19, 0x1A,
0x19, 0x0F, 0xF5, 0x10, 0xAE, 0x18, 0x6D, 0x01, 0x10, 0x56, 0x00, 0x1E,
0x26, 0x71, 0x65, 0x73, 0x78, 0x72, 0xEB, 0x72, 0x52, 0x06, 0xAA, 0xBB,
0xA3, 0xA4, 0x1B, 0xFC, 0xC7, 0x82
]
for i in range(len(data)):
for j in range(len(data) - i -1):
if data[j] > data[j+1]:
tmp = data[j]
data[j] = data[j+1]
data[j+1] = tmp
# for i in data:
# print(f"{hex(i)},",end='')
f = b""
for x in data:
b = x.to_bytes(2,"little") #小端序拆分成单字节
f += b
#print(f.hex())
hex_str = f.hex()
# 将十六进制字符串按每8字节(即16个字符)分块,转为列表
chunk_size = 2
chunks = [hex_str[i:i+chunk_size] for i in range(0, len(hex_str), chunk_size)]
# 将每个块转换为十进制并存入列表
decimal_list = [int(chunk, 16) for chunk in chunks]
result =list(i*0 for i in range(42))
# 打印结果
for d,b,i in zip(decimal_list,box,range(42)):
result[i] = d^b
for i in result:
print(chr(i),end='')
#flag{dea54885-92b4-11ef-b153-3c0af33af908}