西普实验吧部分逆向题writeup(一)


本博客已经弃用,我的新博客地址:http://jujuba.me/

1. baby Crack
本题难度就像它的名字一样,简单得很。下载程序,先用PEID查一下
西普实验吧部分逆向题writeup(一)
文章图片

发现没壳,就是C#写的程序


再用IDA打开,往下拉几行即可看到KEY

西普实验吧部分逆向题writeup(一)
文章图片

KEY: hctf{bABy_CtsvlmE_!}
2.你会吗
下载完先打开看下:
西普实验吧部分逆向题writeup(一)
文章图片

PEID查一下:
西普实验吧部分逆向题writeup(一)
文章图片

别急,用OD打开看看,搜索一下字符串:
西普实验吧部分逆向题writeup(一)
文章图片

居然直接就看到了KEY....DUTCTF{We1c0met0DUTCTF}


3. 阿拉丁神灯
PEID 查了一下 又是C#的 那就直接用IDA打开了
这次往下找啊找感觉找不到,直接到左边的函数列表里看看有没有关键的
找到一个叫WindowsApplication1.Form1__Button1_Click 的函数,点进去,又看到KEY了...
西普实验吧部分逆向题writeup(一)
文章图片

结果又看到了:zhimakaimen@2011
去网站输入之后得到KEY 小明向灯神许愿道~ 灯神啊~ 给我过关的Key吧~ 灯神说道\KEY:UnPack&Crack2011!!


4. 证明自己吧
查壳——没壳——C++编写成的——放入OD调试——搜索字符串——发现成功的字符串附近有跳转函数,改之——在字符串附近下断点——随便输几个数字测试——结果
西普实验吧部分逆向题writeup(一)
文章图片
西普实验吧部分逆向题writeup(一)
文章图片
西普实验吧部分逆向题writeup(一)
文章图片

看到右下角出现了类似KEY的东西,别急,换个数字试试
西普实验吧部分逆向题writeup(一)
文章图片

右下角的KEY类似物变化了,由此可知我们需要的KEY应该是临时算出来的,但是这个又不是注册机。我技术不够不能用OD追出码来,只好用IDA来分析具体算法了
打开IDA,先F5反编译MAIN函数:
西普实验吧部分逆向题writeup(一)
文章图片

我们只看重点,看到gets函数了吧,我们输入的字符串从gets函数进入
看if-else分支的函数调用,if调用的是aGoodTheKey,而else调用的则是aYouDonTGuessIT,很明显,我们要走if分支
去到sub_4011BA函数,F5反编译:



signed int __cdecl sub_401060(const char *a1) { unsigned int v1; // edx@2 unsigned int v2; // edx@4 unsigned int v3; // edx@6 int v5; // [sp+Ch] [bp-10h]@1 int v6; // [sp+10h] [bp-Ch]@1 int v7; // [sp+14h] [bp-8h]@1 __int16 v8; // [sp+18h] [bp-4h]@1 char v9; // [sp+1Ah] [bp-2h]@1v5 = dword_40708C; v6 = dword_407090; v8 = word_407098; v9 = byte_40709A; v7 = dword_407094; if ( strlen(a1) == strlen((const char *)&v5) ) { v1 = 0; if ( strlen(a1) != 0 ) { do a1[v1++] ^= 0x20u; while ( v1 < strlen(a1) ); } v2 = 0; if ( strlen((const char *)&v5) != 0 ) { do *((_BYTE *)&v5 + v2++) -= 5; while ( v2 < strlen((const char *)&v5) ); } v3 = 0; if ( strlen((const char *)&v5) == 0 ) return 1; while ( *((_BYTE *)&v5 + v3 + a1 - (const char *)&v5) == *((_BYTE *)&v5 + v3) ) { ++v3; if ( v3 >= strlen((const char *)&v5) ) return 1; } } return 0; }



我们先看第一段算法:

if ( strlen(a1) == strlen((const char *)&v5) ) { v1 = 0; if ( strlen(a1) != 0 ) { do a1[v1++] ^= 0x20u; while ( v1 < strlen(a1) ); }


看到我们传进来的字符串叫做a1,假如a1的长度等于v5的长度,则开始逐个元素做异或运算,和20异或
我们点进40708C地址看一看v5:
西普实验吧部分逆向题writeup(一)
文章图片


在此要注意的是v5存储的是地址,即需要比较的字符串的首地址,整个字符串应为 68571948 506e5878 546a1958 5e06H


再看第二段:

v2 = 0; if ( strlen((const char *)&v5) != 0 ) { do *((_BYTE *)&v5 + v2++) -= 5; while ( v2 < strlen((const char *)&v5) ); }

v5中的每个字节中存储的值-5


最后一段则是:

v3 = 0; if ( strlen((const char *)&v5) == 0 ) return 1; while ( *((_BYTE *)&v5 + v3 + a1 - (const char *)&v5) == *((_BYTE *)&v5 + v3) ) { ++v3; if ( v3 >= strlen((const char *)&v5) ) return 1; }


可以看出这一段是在比较逐个a1和v5中的元素,while的循环条件前半部分有代码混淆,其实那一堆就相当于*(v3+a1)


现在我们的问题简化为:
我们输入了一段字符串,假设叫code
encode=code^20
当encode=str-5时条件就成立,此时的code就是我们想要的KEY
我们还需要知道的就是一个数连续对另一个数求异或两个,此时得到的数不变
所以我们只要把(str-5)^20就能得到key了


C++代码如下:

#include using namespace std; int main(void) { string code="\x68\x57\x19\x48\x50\x6e\x58\x78\x54\x6a\x19\x58\x5e\x06"; for(int i=0; i<14; i++) code[i]=(code[i]-5)^0x20; cout<

输出结果:
西普实验吧部分逆向题writeup(一)
文章图片


顺便贴个Python代码:

code=(0x68,0x57,0x19,0x48,0x50,0x6e,0x58,0x78,0x54,0x6a,0x19,0x58,0x5e,0x06) for i in code: i=(i-5)^0x20 print chr(i)


西普实验吧部分逆向题writeup(一)
文章图片



KEY:Cr4ckIsSoE4sy!










【西普实验吧部分逆向题writeup(一)】

    推荐阅读