专家点评
下面由看雪专家:海风月影给大家带来第二道赛题的点评。
海风月影:第二题属于小巧玲珑型题目,大小24KB,逆向工作量不大,本人很喜欢~ —> [24K纯金CTF]
虽然代码量小,但是作者设计的思路新颖,用了一张乱序的[0-255]表,隐藏掉前8字节,作为key的前8字节,通过算法扩展成256*256的表,统计256张256的表中,固定0,14,40,79位置上不为0的个数。对乱序表进行变形取前8字节,利用key的后8字节查表解密,最终变成 “GoodJob~” 这个明文提示,则验证成功。
如果把乱序的表认为是内置了RC4的密钥的置换表,整体算法看上去像是一个类似RC4的加密变换,先把前8个字节穷举出来,再解密得到明文字符串。
出题团队简介
lelfei(HU1战队队长),crack爱好者。学生时代对电脑产生了浓厚的兴趣,经历了很长时间的游戏沉迷后,开始慢慢转向学习技术,工作后自学了ASM、VB、VC、HTML、ASP、Python等语言的入门。对单机的逆向分析、算法比较感兴趣。
赛题设计思路
设计说明:
本题是个数字替换的小游戏。
预设一个【0-255】的乱序表,隐藏前8字节。用户输入32位16进制字符串,转换成16字节数值,前8字节填入乱序表。验证过程分三步:
1、统计表格,每一位分别按*p++和**p查表,查8次后,统计所有能到达的格子,形成256*256的方阵,分别统计第0、14、40、79列,验证col0==169 && col14==172 && col40==167 && col79>200。
2、变形表格,每一位按**p循环替换,要求256步之内能回到当前值。
3、验证表格,取表格前8位,分别按用户输入的后8位的二进制值进行查表,为0时取**p,为1时取*p++,查表8次后,验证结果是否为“GoodJob~”。成功则输出“GoodJob~”。否则输出“TryAgain”。
本题使用VC6+WTL制作。
1、程序没有任何ANTI,可以直接在IDA中查看源码,找到上述三步验证。
2、根据验证第2步分析可知,256个数在256个位置全部都能循环替换回来,对每一个数都必然存在*p=i这一步,也就是说0-255这256个数都要存在,统计给出的258位,找出缺失的8位为:[30, 40, 75, 109, 140, 163, 210, 251]。
3、把8位进行排列,分别用第1步的算法进行验证,一共有40320种组合,数量级很小,很快就能穷举出结果,得到唯一解:[0x4B, 0x6D, 0x28, 0x8C, 0xFB, 0xD2, 0x1E, 0xA3]。
4、把8位值放入256数表格,运行第2步进行表格变换。
5、取变换后的表格的前8位[193, 155, 127, 88, 100, 213, 119, 33],按第1步的算法列举出每一位能到达的值,然后查表找出“GoodJob~”每一位的运行步骤为[0x9D, 0x6B, 0xEA, 0x2F, 0xA4, 0x08, 0xBC, 0x22],都是唯一解。
6.把前8位的解与后面的运行步骤组合并按输入逆序排列,得到答案:B4D682C8BF2DE13AD9B6AEF24A80CB22。
赛题解析
本赛题解析由看雪论坛 HHHso 给出:
正向检验算法还算直观,其唯一解的数学原理未知,但不妨碍我们直接爆破。
一
正向算法
1、着力点
我们直接关注图1-1中代码,通过GetDlgItemTextA交叉索引得到。
通过基本分析,我们得到:
(1)Hi_this_obuf_icode_len__hex2bytes 将输入的32字节长lv_code通过16进制转换胃16字节,应该注意lv_code与转换后的Hi_codeLH的差异性,如:
input code hex:= "0123456789ABCDEF" + "0123456789ABCDEF"
经过转换
inner code bin:= 1032547698BADCFE :: 1032547698BADCFE
unsigned char inner_code_bin[0x10] = {0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, ...}
即'01'转换为0x10,'23'转换为0x32,以此类推。
(2)转换后的16字节Hi_codeLH ,我们分为codeL,codeH高低(各8字节)两部分,其中抵8字节codeL填充了codeLSalt数组;
(3)Hi_last_check函数是核心检验函数。
着手代码片段
2、核心校验框架
(1)第一部分,检测codeLSalt的有效性,codeLSalt大小为0x100字节,如上所述,前8字节来自输入的codeL。
(2)第二部分,对codeLSalt进行变换;
(3)第三部分,利用codeLSalt和codeH对bsuk进行变换,bsuk初始值为codeLsalt前8字节;
(4)第四部分,变换后的bsuk是否为“GoodJob~”。
Hi_last_check主要业务逻辑
int __thiscall Hi_last_check(HWND *this, char *codeH)
{
int lv_i; // ebp
char *v3; // eax
int *v4; // esi
char *btsx; // ecx
int v6; // edi
_BYTE *v7; // ecx
int v8; // edx
char *v9; // eax
int v10; // ecx
int v11; // esi
int v12; // eax
unsigned __int8 v13; // dl
int v14; // edi
int v15; // eax
int v16; // ecx
int chi; // esi
int i; // eax
char v19; // dl
char lv_a; // [esp+10h] [ebp-Ch]
char lv_b; // [esp+11h] [ebp-Bh]
char lv_c; // [esp+12h] [ebp-Ah]
unsigned __int8 lv_d; // [esp+13h] [ebp-9h]
char (*lv_gbsptr)[256]; // [esp+14h] [ebp-8h]
//-----------------第一部分开始
lv_a = 0;
lv_b = 0;
lv_c = 0;
lv_d = 0;
lv_i = 1;
lv_gbsptr = Hi_gbsA;
do
{
Hi_bts[0] = codeLSalt[lv_i - 1];
Hi_bts[1] = lv_i;
v3 = Hi_bts;
v4 = &Hi_cns;
btsx = &Hi_bts[Hi_cns];
do
{
v6 = *v4;
if ( *v4 > 0 )
{
do
{
v7 = btsx + 1;
*(v7 - 1) = codeLSalt[(unsigned __int8)*v3];
*v7 = *v3 + 1;
btsx = v7 + 1;
++v3;
--v6;
}
while ( v6 );
}
++v4;
}
while ( (int)v4 < (int)&Hi_cns_end );
v8 = 256;
do
{
++(*lv_gbsptr)[(unsigned __int8)*v3++];
--v8;
}
while ( v8 );
++lv_i;
++lv_gbsptr;
}
while ( lv_i - 1 < 256 );
v9 = &Hi_gbsA[0][40];
v10 = 256;
do
{
if ( *(v9 - 40) )
++lv_a;
if ( *(v9 - 26) )
++lv_b;
if ( *v9 )
++lv_c;
if ( v9[39] )
++lv_d;
v9 += 256;
--v10;
}
while ( v10 );
if ( lv_a == (char)0xA9 && lv_b == (char)0xAC && lv_c == (char)0xA7 && lv_d > 0xC8u )
{
//-------------------------第二部分开始
v11 = 0;
while ( 2 )
{
v12 = 0;
while ( (unsigned __int8)codeLSalt[v12] != v11 )
{
if ( ++v12 >= 256 )
goto LABEL_32;
}
v13 = codeLSalt[v11];
v14 = 0;
v15 = v11;
if ( v11 != v13 )
{
do
{
++v14;
v16 = (unsigned __int8)codeLSalt[v15];
codeLSalt[v15] = codeLSalt[v16];
v15 = v16;
if ( v14 >= 256 )
return 0;
}
while ( v11 != (unsigned __int8)codeLSalt[v16] );
}
codeLSalt[v15] = v13;
LABEL_32:
if ( ++v11 < 256 )
continue;
break;
}
//------------------------------第三部分开始
chi = 0;
*(_QWORD *)&bsuk = *(_QWORD *)codeLSalt;
do
{
for ( i = 0; i < 8; ++i )
{
if ( chi >= 8 )
{
if ( !i || i == 7 )
--*(&bsuk + i);
}
else
{
if ( (codeH[i] & 1) != 0 )
v19 = *(&bsuk + i) + 1;
else
v19 = codeLSalt[(unsigned __int8)*(&bsuk + i)];
*(&bsuk + i) = v19;
codeH[i] = (unsigned __int8)codeH[i] >> 1;
}
}
++chi;
}
while ( chi < 9 );
//-------------------------------第四部分开始,作最后检测校对
if ( !Hi_strncmp(&bsuk, bsC, 8) )
{
MessageBoxA(this[1], bsC, Caption, 0x40u);
return 1;
}
}
return 0;
}
二
直接爆破
针对核心算法操作的四个部分(忽略最后的strncmp,实际是三部分)进行爆破。
1、有效的codeLSalt
如图,对codeLSalt的有效性检测,实际也分为四各小步骤,基本算法描述为:
(1)定义全局变量
unsigned char codeLSalt[0x100] = {...};
unsigned char bts[0x200] = {0}; //细分各小段长度依次为 0x02+0x04+0x08+0x10+0x20+0x40+0x80+0x100+0x02
int cns[8]={0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x00} //
unsigned char gbsA[0x100][0x100] = {...};
(2)演化
0,1,...0xFF =
codeLSalt[i],bts[1]=i+1; 即初始化bts最开始的两字节片段, =
然后利用codeLSalt和cns,逐段衍生后续片段,直到完成bts中最后0x100大小片段的衍生
(3)统计
对于每个i对应codeLSaolt[i]衍生的最后0x100大小片段中出现的数字,进行个数统计,记录仔gbsA[i]中,
(3.1)举例说明
{ =
0x4B,0x6D,0x28,0x8C,0xFB,0xD2,0x1E,0xA3,0xA2,0x9B,0xF4,0xDF,0xAC,0x7C,0xA1,0xC6,
0x16,0xD0,0x0F,0xDD,0xDC,0x73,0xC5,0x6B,0xD1,0x96,0x47,0xC2,0x26,0x67,0x4E,0x41,
0x82,0x20,0x56,0x9A,0x6E,0x33,0x92,0x88,0x29,0xB5,0xB4,0x71,0xA9,0xCE,0xC3,0x34,
0x50,0x59,0xBF,0x2D,0x57,0x22,0xA6,0x30,0x04,0xB2,0xCD,0x36,0xD5,0x68,0x4D,0x5B,
0x45,0x9E,0x85,0xCF,0x9D,0xCC,0x61,0x78,0x32,0x76,0x31,0xE3,0x80,0xAD,0x39,0x4F,
0xFA,0x72,0x83,0x4C,0x86,0x60,0xB7,0xD7,0x63,0x0C,0x44,0x35,0xB3,0x7B,0x19,0xD4,
0x69,0x08,0x0B,0x1F,0x3D,0x11,0x79,0xD3,0xEE,0x93,0x42,0xDE,0x23,0x3B,0x5D,0x8D,
0xA5,0x77,0x5F,0x58,0xDB,0x97,0xF6,0x7A,0x18,0x52,0x15,0x74,0x25,0x62,0x2C,0x05,
0xE8,0x0D,0x98,0x2A,0x43,0xE2,0xEF,0x48,0x87,0x49,0x1C,0xCA,0x2B,0xA7,0x8A,0x09,
0x81,0xE7,0x53,0xAA,0xFF,0x6F,0x8E,0x91,0xF1,0xF0,0xA4,0x46,0x3A,0x7D,0x54,0xEB,
0x2F,0xC1,0xC0,0x0E,0xBD,0xE1,0x6C,0x64,0xBE,0xE4,0x02,0x3C,0x5A,0xA8,0x9F,0x37,
0xAF,0xA0,0x13,0xED,0x1B,0xEC,0x8B,0x3E,0x7E,0x27,0x99,0x75,0xAB,0xFE,0xD9,0x3F,
0xF3,0xEA,0x70,0xF7,0x95,0xBA,0x1D,0x40,0xB0,0xF9,0xE5,0xF8,0x06,0xBC,0xB6,0x03,
0xC9,0x10,0x9C,0x2E,0x89,0x5C,0x7F,0xB1,0x1A,0xD6,0x90,0xAE,0xDA,0xE6,0x5E,0xB9,
0x84,0xE9,0x55,0xBB,0xC7,0x0A,0xE0,0x66,0xF2,0xD8,0xCB,0x00,0x12,0xB8,0x17,0x94,
0x6A,0x4A,0x01,0x24,0x14,0x51,0x07,0x65,0x21,0xC8,0x38,0xFD,0x8F,0xC4,0xF5,0xFC,
};
0,则有bts[0x200] = { =
4B 01
E3 4C 6D 02
BB E4 80 4D 3B 6E 28 03
75 BC
C7 E5 E8 81 AD 4E 36 3C 5D 6F 29 29 8C 04
97 76
AB BD 40 C8 0A E6 F2 E9 0D 82 A8 AE 39 4F A6 37
D5 3D 7B 5E 8D 70 B5 2A B5 2A 2B 8D FB 05
91 98
F6 77 3C AC FE BE 45 41 B0 C9 F4 0B E0 E7 01 F3
D8 EA 7C 0E 98 83 BE A9 9F AF B2 3A 4F 50 6C A7
30 38 5C D6 68 3E 74 7C 19 5F A7 8E A5 71 EC B6
B4 2B EC B6 B4 2B 71 2C A7 8E FD FC D2 06
E7 92
F1 99 07 F7 7A 78 D5 3D 5A AD F5 FF D9 BF CC 46
9E 42 AF B1 F9 CA 14 F5 DF 0C 84 E1 66 E8 6D 02
24 F4 1A D9 CB EB 25 7D A1 0F F1 99 2A 84 D9 BF
E4 AA EB A0 37 B0 13 B3 CD 3B 4F 50 FA 51 23 6D
64 A8 50 31 04 39 B3 5D 7F D7 EE 69 4D 3F DB 75
25 7D 96 1A D4 60 64 A8 8A 8F E1 A6 77 72 12 ED
8B B7 1B B5 71 2C 12 ED 8B B7 1B B5 71 2C 77 72
A9 2D 64 A8 8A 8F C4 FE 8F FD 9C D3 1E 07
66 E8
53 93 4A F2 F0 9A A3 08 65 F8 15 7B 18 79 5C D6
68 3E 44 5B A8 AE 51 F6 FC 00 D6 DA 3F C0 06 CD
61 47 54 9F 85 43 37 B0 A0 B2 C8 FA E5 CB DC 15
51 F6 B9 E0 AC 0D 43 85 E9 E2 79 67 F2 E9 3B 6E
28 03 6E 25 14 F5 47 1B D6 DA F8 CC 00 EC 33 26
62 7E C1 A2 C6 10 4A F2 F0 9A B4 2B 43 85 D6 DA
3F C0 C7 E5 02 AB 00 EC 2F A1 30 38 AF B1 DD 14
ED B4 BC CE 36 3C 4F 50 FA 51 38 FB 72 52 9A 24
3B 6E 3D 65 BE A9 FA 51 59 32 FB 05 B2 3A ED B4
7B 5E 05 80 B1 D8 17 EF 93 6A AD 4E 5B 40 AE DC
97 76 33 26 62 7E 8E 97 47 1B 89 D5 69 61 3D 65
BE A9 1C 8B 09 90 E9 E2 6C A7 7A 78 5F 73 0F 13
B8 EE CA 8C 3E B8 C2 1C EC B6 77 72 A9 2D 0F 13
B8 EE CA 8C 3E B8 C2 1C EC B6 77 72 A9 2D 7A 78
5F 73 E4 AA CE 2E 3D 65 BE A9 1C 8B 09 90 95 C5
F5 FF 09 90 C4 FE 3A 9D 2E D4 4E 1F A3 08
00 00
}
0, =
4B 01;
2,得到codeLSalt[0x4B],0x4B+1,codeLSalt[0x01],0x01+1,则对应 E3 4C 6D 02; =
0x04,得到BB E4 80 4D 3B 6E 28 03 ; =
以此类推,直到得到最后0x100长的片段。
由最后0x100长片段,我们得到gbsA[i];
gbsA[i][0] = 0x03,表示统计最后0x100长片段中0x00出现了3次,
=0x00,以此类推 =
{ =
03 00 01 01 00 02 01 00 02 03 00 00 00 01 00 02
01 00 00 02 02 02 00 01 01 00 00 02 04 00 00 01
00 00 00 00 01 01 02 00 01 00 00 01 00 02 02 01
01 00 01 02 00 00 01 01 02 00 02 02 01 03 03 02
01 00 00 03 01 00 00 03 00 00 02 00 00 00 02 01
01 04 01 01 01 00 00 00 00 01 00 02 01 00 01 02
00 02 02 00 00 04 01 01 01 01 01 00 01 00 03 00
00 00 03 02 00 00 01 02 02 02 02 02 00 00 02 00
01 00 00 00 00 03 00 00 00 01 00 02 02 00 01 00
03 00 00 02 00 01 00 02 00 00 03 00 00 01 00 01
01 01 01 02 00 00 00 01 01 05 01 01 01 01 02 01
01 02 02 00 03 00 02 00 04 01 00 00 01 00 03 00
02 01 02 00 01 01 01 01 01 00 02 01 01 01 02 00
00 00 00 00 01 01 04 00 01 00 03 00 02 01 00 00
01 00 02 00 01 02 00 00 01 03 00 00 04 02 02 01
02 00 03 00 00 02 02 00 02 00 03 02 01 00 01 01
}
(4)针对性统计,校对
0,1,..0xFF =
14, 40, 79分别出现的总此书,依次记录为a,b,c,d
= 0xA9 && b == 0xAC && c == 0xA7 && d > 0xC8,如果满足,则codeLSalt有效 =
枚举爆破得到有效codeLSalt,如图,我们直到codeLSalt的大小为0x100,且初始末端的0x100-8字节都已经固定,通过观察,我们可以判定,其为0x00-0xFF的非重复排列,作为基准映射表使用。
由此出发,我们可以确定codeLSalt前8字节的取值集合,执行下述idapython。
cst = set(ida_bytes.get_bytes(0x404000+8,0x100-8)) #cs mapping's tail bytes' set
csa = set([i for i in range(0x100)]) #cs mapping's all bytes' set
csl = list(csa - cst) #cs mapping's first head 8-bytes' set
#Out:==> [30, 40, 75, 109, 140, 163, 210, 251]
from itertools import permutations
pl = [p for p in permutations(csl, 8)]
len(pl)
#Out==》 40320
#here we try to save all 40320 cases of {cs[i]===inner_code_bin[i] | i = 0,1,...,7} to pbs.bin file
#
with open(r'D:CTF2021KCTFPKCTF02pbs.bin','wb') as fout:
fout.write(b''.join([bytes(list(p)) for p in pl]))
codeLSalt初始值
(1)编译执行附件find_codeLSalt.c代码,如下
cl find_codeLSalt.c cutils.c
ind_codeLSalt.exe 0 40230 .pbs.bin
(2)我们得到
find_codeLSalt.exe 0 40230 .pbs.bin
[Start Time]: 2021/11/17 22:38:10
Read pbs from .pbs.bin ok.
Check from 0 to 40230 start:
=======> Found i := 12399 at 2021/11/17 22:38:35
pbs[i][] = {0x4B,0x6D,0x28,0x8C,0xFB,0xD2,0x1E,0xA3};
Check from 0 to 40230 end!
[End Time]: 2021/11/17 22:39:31
(3)即我们仔40230种排列中,找到唯一的有效codeL为 0x4B,0x6D,0x28,0x8C,0xFB,0xD2,0x1E,0xA3,这位codeLSalt的前8字节,
其余字节参考图1-4内容。
于是我们由codeL得到code的前16字节输入为 "B4D682C8BF2DE13A"
(1)编译执行附件
cl gen_xcs.c cutils.c
gen_xcs.exe 12399 .pbs.bin
(2)我们得到第二部分codeLSalt的变换xcs
gen_xcs.exe 12399 .pbs.bin
[Start Time]: 2021/11/17 22:48:42
Read pbs from .pbs.bin ok.
The cs is:
0x4B,0x6D,0x28,0x8C,0xFB,0xD2,0x1E,0xA3,0xA2,0x9B,0xF4,0xDF,0xAC,0x7C,0xA1,0xC6,
0x16,0xD0,0x0F,0xDD,0xDC,0x73,0xC5,0x6B,0xD1,0x96,0x47,0xC2,0x26,0x67,0x4E,0x41,
0x82,0x20,0x56,0x9A,0x6E,0x33,0x92,0x88,0x29,0xB5,0xB4,0x71,0xA9,0xCE,0xC3,0x34,
0x50,0x59,0xBF,0x2D,0x57,0x22,0xA6,0x30,0x04,0xB2,0xCD,0x36,0xD5,0x68,0x4D,0x5B,
0x45,0x9E,0x85,0xCF,0x9D,0xCC,0x61,0x78,0x32,0x76,0x31,0xE3,0x80,0xAD,0x39,0x4F,
0xFA,0x72,0x83,0x4C,0x86,0x60,0xB7,0xD7,0x63,0x0C,0x44,0x35,0xB3,0x7B,0x19,0xD4,
0x69,0x08,0x0B,0x1F,0x3D,0x11,0x79,0xD3,0xEE,0x93,0x42,0xDE,0x23,0x3B,0x5D,0x8D,
0xA5,0x77,0x5F,0x58,0xDB,0x97,0xF6,0x7A,0x18,0x52,0x15,0x74,0x25,0x62,0x2C,0x05,
0xE8,0x0D,0x98,0x2A,0x43,0xE2,0xEF,0x48,0x87,0x49,0x1C,0xCA,0x2B,0xA7,0x8A,0x09,
0x81,0xE7,0x53,0xAA,0xFF,0x6F,0x8E,0x91,0xF1,0xF0,0xA4,0x46,0x3A,0x7D,0x54,0xEB,
0x2F,0xC1,0xC0,0x0E,0xBD,0xE1,0x6C,0x64,0xBE,0xE4,0x02,0x3C,0x5A,0xA8,0x9F,0x37,
0xAF,0xA0,0x13,0xED,0x1B,0xEC,0x8B,0x3E,0x7E,0x27,0x99,0x75,0xAB,0xFE,0xD9,0x3F,
0xF3,0xEA,0x70,0xF7,0x95,0xBA,0x1D,0x40,0xB0,0xF9,0xE5,0xF8,0x06,0xBC,0xB6,0x03,
0xC9,0x10,0x9C,0x2E,0x89,0x5C,0x7F,0xB1,0x1A,0xD6,0x90,0xAE,0xDA,0xE6,0x5E,0xB9,
0x84,0xE9,0x55,0xBB,0xC7,0x0A,0xE0,0x66,0xF2,0xD8,0xCB,0x00,0x12,0xB8,0x17,0x94,
0x6A,0x4A,0x01,0x24,0x14,0x51,0x07,0x65,0x21,0xC8,0x38,0xFD,0x8F,0xC4,0xF5,0xFC,
The xcs is:
0xC1,0x9B,0x7F,0x58,0x64,0xD5,0x77,0x21,0x74,0xEB,0x14,0xBF,0xDF,0x25,0x5A,0x37,
0x85,0x2C,0xAF,0x8C,0xDA,0x26,0xE2,0x7A,0x87,0x4C,0x60,0x99,0x54,0x3C,0x95,0xC0,
0xB9,0x0C,0xBC,0x0E,0xE7,0x2D,0x86,0xBE,0x67,0xD3,0xD8,0xFC,0x30,0xB6,0xC8,0x57,
0x1E,0x62,0x3E,0xCE,0xA0,0xCD,0xF5,0xEE,0xA7,0xCF,0x45,0xFE,0xD0,0x80,0x05,0xAD,
0x13,0xF3,0xB7,0x6B,0x22,0x2B,0xBD,0x69,0x42,0x4B,0xA5,0xEA,0xA6,0xD2,0x6F,0x4F,
0x4E,0x07,0xE1,0x36,0x01,0xB5,0xAA,0xB1,0x94,0x0B,0x35,0x3A,0xC7,0x49,0x53,0x82,
0xC3,0x7B,0x32,0xFF,0x19,0xC4,0xF1,0xC9,0xE8,0xF7,0x56,0x15,0xA3,0x46,0x89,0x43,
0x9D,0x8F,0x20,0xEF,0xBB,0x2A,0xCB,0x09,0x93,0x4A,0x1C,0xE3,0x33,0xD1,0xE0,0x1D,
0x72,0x7C,0x27,0xE9,0x17,0x28,0x6D,0x6A,0xD9,0x00,0x9A,0xE5,0x63,0xDE,0x23,0x9F,
0x0D,0x47,0x3B,0x65,0x08,0x84,0x6C,0x1A,0x88,0x12,0xA1,0xA4,0xB3,0x18,0x24,0x1B,
0xD7,0x44,0xDB,0xAC,0x6E,0x7D,0x51,0x5E,0xED,0x50,0xD6,0x11,0x5B,0x9C,0xB4,0x68,
0x3D,0x2F,0x03,0x40,0xBA,0x2E,0xCA,0x02,0xE6,0xA8,0xEC,0x83,0x06,0x5D,0xB8,0x4D,
0x97,0x66,0xF0,0xFB,0x8A,0x55,0xAB,0xB2,0x04,0xFA,0x0A,0x31,0x71,0xCC,0x8B,0x73,
0xA9,0x48,0x5C,0xF9,0x98,0xE4,0xC6,0x34,0xC5,0x7E,0x81,0x75,0x90,0x1F,0x92,0x3F,
0x9E,0x10,0x29,0x52,0x39,0xF4,0x41,0x78,0x5F,0x16,0x79,0xC2,0xB0,0xDD,0xF2,0x61,
0x0F,0x70,0xD4,0x91,0xDC,0xF6,0xF8,0xFD,0x59,0x38,0x8D,0x96,0xAE,0x8E,0x76,0xA2,
[End Time]: 2021/11/17 22:48:42
第三部分如下图,bsuk初始值为xcs的前8字节,即0xC1,0x9B,0x7F,0x58,0x64,0xD5,0x77,0x21;其经过9次变换,得到最终的bsuk;
每次通过codeLSalt的变换受codeH的影响;仔细分析我们可以发现,实际上bsuk各个字节的变换时独立的,受codeH对应单字节的影响;
于是我们可以枚举codeH[i]的值,从0x00到0xFF,对bsuk进行变换,如果得到最终“GoodJob~”对应字节,则表示找到了对应的codeH[i]
bsuk的变换
(1)编译执行附件 find_codeH.c代码
cl find_codeH.c cutils.c
find_codeH.exe GoodJob~
cH[0]:
0x9D
cH[1]:
0x6B
cH[2]:
0xEA
cH[3]:
0x2F
cH[4]:
0xA4
cH[5]:
0x08
cH[6]:
0xBC
cH[7]:
0x22
(2) 于是我们得到codeH = [0x9D,0x6B,0xEA,0x2F,0xA4,0x08,0xBC,0x22]
即codeH的输入部分为D9B6AEF24A80CB22
三
总结
第三题《蒙混过关》正在火热进行中,
球分享
球点赞
球在看
原文始发于微信公众号(看雪学苑):看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析