本博客已经弃用,我的新博客地址:http://jujuba.me/
1. baby Crack
本题难度就像它的名字一样,简单得很。下载程序,先用PEID查一下
文章图片
发现没壳,就是C#写的程序
再用IDA打开,往下拉几行即可看到KEY
文章图片
KEY: hctf{bABy_CtsvlmE_!}
2.你会吗
下载完先打开看下:
文章图片
PEID查一下:
文章图片
别急,用OD打开看看,搜索一下字符串:
文章图片
居然直接就看到了KEY....DUTCTF{We1c0met0DUTCTF}
3. 阿拉丁神灯
PEID 查了一下 又是C#的 那就直接用IDA打开了
这次往下找啊找感觉找不到,直接到左边的函数列表里看看有没有关键的
找到一个叫WindowsApplication1.Form1__Button1_Click 的函数,点进去,又看到KEY了...
文章图片
结果又看到了:zhimakaimen@2011
去网站输入之后得到KEY 小明向灯神许愿道~ 灯神啊~ 给我过关的Key吧~ 灯神说道\KEY:UnPack&Crack2011!!
4. 证明自己吧
查壳——没壳——C++编写成的——放入OD调试——搜索字符串——发现成功的字符串附近有跳转函数,改之——在字符串附近下断点——随便输几个数字测试——结果
文章图片
文章图片
文章图片
看到右下角出现了类似KEY的东西,别急,换个数字试试
文章图片
右下角的KEY类似物变化了,由此可知我们需要的KEY应该是临时算出来的,但是这个又不是注册机。我技术不够不能用OD追出码来,只好用IDA来分析具体算法了
打开IDA,先F5反编译MAIN函数:
文章图片
我们只看重点,看到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:
文章图片
在此要注意的是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<
输出结果:
文章图片
顺便贴个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)
文章图片
KEY:Cr4ckIsSoE4sy!
【西普实验吧部分逆向题writeup(一)】