1625-5 王子昂 总结《2017年9月17日》 【连续第350天总结】
A. XCTF(武汉站)-Reverse
B.
EasyHook
刚开始看这个名字还以为要注入DLL啥的呢(:з」∠)忐忑不安地打开发现结构挺简单:
int __cdecl main(int argc, const char **argv, const char **envp)
{
int result; // eax@2
HANDLE FileHandle; // eax@3
DWORD NumberOfBytesWritten; // [sp+4h] [bp-24h]@3
char Buffer; // [sp+8h] [bp-20h]@1
sub_401370(aPleaseInputFla);
scanf(a31s, &Buffer);
if ( strlen(&Buffer) == 19 ) // 输入长度为19
{
sub_401220(); // 将Re_writeFile函数的地址覆盖WriteFile
FileHandle = CreateFileA(FileName, 0x40000000u, 0, 0, 2u, 0x80u, 0);// 创建文件
WriteFile(FileHandle, &Buffer, 0x13u, &NumberOfBytesWritten, 0);// 执行WriteFile函数,实际上是Re_writeFile
sub_401240(&Buffer, &NumberOfBytesWritten); // 比较函数(伪)
if ( NumberOfBytesWritten == 1 )
sub_401370(aRightFlagIsYou); // 错误提示
else
sub_401370(aWrong);
system(aPause);
result = 0;
}
else
{
sub_401370(aWrong);
system(aPause);
result = 0;
}
return result;
}
关键就在sub_401220函数上
本来以为它是处理函数,但是打开以后发现通过API取得了kernel32.dll中WriteFile的地址,之后就不太清晰了
OD动态调试也可以发现,sub_401220前后并没有使得buffer的值发生改变
单步调试发现关键变化发生于call WriteFile
这明明是个API,怎么会改变文件内容呢
F7跟进去发现转入了用户模块的sub_401080
这下就清楚了,sub_401220取到了WriteFile的地址,然后用sub_401080覆盖之;使得调用WriteFile的时候变为调用sub_401080
这个就是hook技术了
接下来分析sub_401080:调用了sub_401000处理input,然后就执行真正的WriteFile
而在sub_401000中终于是真正的处理算法:
signed int __cdecl flag(int str, signed int length)
{
char v2; // al@1
char v3; // bl@5
char v4; // cl@9
int v5; // eax@10
signed int result; // eax@13
v2 = 0;
if ( length > 0 )
{
do
{
if ( v2 == 18 ) // 第19个字符异或0x13
{
*(_BYTE *)(str + 18) ^= 0x13u;
}
else
{
if ( v2 % 2 ) // 偶数字符(下标为奇数),str[n] = n ^ (str[n]-i)
v3 = *(_BYTE *)(v2 + str) - v2;
else
v3 = *(_BYTE *)(v2 + str + 2); // 奇数字符(下标为偶数),str[n] = n ^ str[n+2]
*(_BYTE *)(v2 + str) = v2 ^ v3;
}
++v2;
}
while ( v2 < length );
}
v4 = 0;
if ( length <= 0 )
{
LABEL_13:
result = 1;
}
else
{
v5 = 0;
while ( byte_40A030[v5] == *(_BYTE *)(v5 + str) )// 验证处理过后的结果是否与byte_40a030相等
{
v5 = ++v4;
if ( v4 >= length )
goto LABEL_13;
}
result = 0;
}
return result;
}
最下面的地方循环比较,刚开始没有注意,成功的话会返回1否则返回0
观察了一下返回1的话会使得
*lpNumberOfBytesWritten = 1
算法比较简单,稍微绕一下就能写出还原脚本
而从main函数中可以看到,要提示正确,需要NumberOfBytesWritten == 1
这个变量则取决于sub_401240
打开可以看到,是一个字符串比较循环:
input的另一边是“This_is_not_the_flag”
放入解密脚本发现上字符串的长度是20,与输入不对应,做出来的字符串也有些问题
比如说,解密后文本的第一个字符不会影响源字符串,而最后一个字符则会决定最后一个和倒数第三个字符;
‘a’对应的倒数第三个字符是’b’,意味着没有与其对应的原字符串
检查了好久算法没有出问题,花去了两三个小时
本来在考虑是否要爆破通过前一个验证,
后来突然想起来在sub_401000中最后还有一个验证循环,虽然return不大对,不过死马当活马医了
用IDC脚本将值dump下来,进行解密
嘿,还真的生成了有意义的字符串:
lag{Ho0k_w1th_Fun}
第一个字符很明显是a,提交正确
虽然后面那个字符串已经明白告诉This is not the flag了结果还是掉坑里了OTZ
看起来lpNumberOfBytesWritten是NumberOfBytesWritten的指针,因此取值赋1也可以达到效果
如果不跳坑里能拿900+Pt的,被拖了两三个小时就只有500Pt啦,有点可惜~
练习不够,对lp不够敏感,还要慢慢学习
附上python加解密脚本:
# origin pro
s = "1234567890123456789"
flag = ''
for i in range(18):
if(i%2):
flag += chr(i ^ (ord(s[i])-i))
else:
flag += chr(i ^ (ord(s[i+2])))
flag += chr(ord(s[18]) ^ 0x13)
print flag
# rev pro
# s = "This_is_not_the_flag" 被坑了许久的假字符串
# s = "307234?69.9,9*9()6*" 1-9的验证加密结果
s = "ajygkFm.\x7f_~-SV{8mLn" byte_40A030的真字符串
flag = ['' for x in range(19)]
flag[18] = chr(ord(s[18]) ^ 0x13)
# s[18] = flag[18]
for i in range(18):
i=17-i
if((i)%2):
flag[i] = chr((ord(s[i]) ^ i) + i)
else:
if(i>1):
flag[i] = chr(ord(s[i-2]) ^ (i-2))
print ''.join(flag)
C. 明日计划
ARP欺骗
本文介绍了在WHCTF(武汉站)-Reverse挑战中遇到的EasyHook技术。作者通过分析代码发现,程序使用hook技术替换WriteFile API,实现在调用WriteFile时执行自定义的sub_401080函数。通过对sub_401080和sub_401000的分析,理解了输入处理算法,并最终成功解密得到了正确的字符串。然而,在过程中因对某些细节不够敏感,导致了一些时间的浪费。
1万+

被折叠的 条评论
为什么被折叠?



