好友
阅读权限30
听众
最后登录1970-1-1
|
本帖最后由 skywilling 于 2017-12-25 21:59 编辑
0x00前言
考研结束了,终于可以有一段闲暇的时间了。在睡了一天后,不忘发个帖子,疏解一下空虚寂寞的心情,再加上今天是圣诞节。这个题目其实在暑假就已经解出来了,是准备等到考完研再发出来的,也就是现在。
下面开始切入正题
0x01运行
运行很简单,输入错误即返回fail提示。
0x02静态分析
首先放到IDA中看一下,入口在哪里
三个关键字也很显眼
根据"please input key:"找到输入口,直接F5
[C] 纯文本查看 复制代码 int sub_4014B0()
{
int v0; // eax@1
int v1; // ecx@1
int v2; // eax@1
int v3; // ebx@1
signed int v4; // eax@2
unsigned int v5; // ecx@3
int v6; // edx@3
int v7; // eax@5
int v8; // esi@5
int v9; // edx@5
int v10; // eax@5
char *v11; // edi@9
int v12; // ecx@9
int v13; // esi@9
void *v14; // esi@11
int v15; // eax@11
int v16; // ebx@11
const char *v17; // edx@14
int v18; // eax@15
int v19; // eax@17
char *v20; // ecx@19
unsigned int v21; // eax@22
unsigned int v22; // ecx@24
signed int v24; // [sp+10h] [bp-1008h]@3
int v25; // [sp+14h] [bp-1004h]@5
int v26; // [sp+18h] [bp-1000h]@1
void *Memory; // [sp+1Ch] [bp-FFCh]@9
int v28; // [sp+20h] [bp-FF8h]@5
int v29; // [sp+24h] [bp-FF4h]@5
int v30; // [sp+28h] [bp-FF0h]@1
int v31; // [sp+2Ch] [bp-FECh]@2
void *v32; // [sp+30h] [bp-FE8h]@1
int v33; // [sp+40h] [bp-FD8h]@1
unsigned int v34; // [sp+44h] [bp-FD4h]@1
char v35; // [sp+48h] [bp-FD0h]@1
__int128 v36; // [sp+FE8h] [bp-30h]@3
__int128 v37; // [sp+FF8h] [bp-20h]@5
int v38; // [sp+1014h] [bp-4h]@1
v0 = sub_401A60(std::cout, "please input key:");
std::basic_ostream<char,std::char_traits<char>>::operator<<(v0, sub_401C90);
v33 = 0;
v34 = 15;
LOBYTE(v32) = 0;
v38 = 0;
sub_401DC0(std::cin, (int)&v32);
sub_401300((unsigned int)&v32, (int)&v35);
sub_401120((int)&v26, (int)&v35, v1); // 将堆栈数据复制到数据段
v2 = 999;
LOBYTE(v38) = 1;
v3 = v26;
v30 = 999;
while ( 2 )
{
v4 = (unsigned __int8)byte_403230[v2];
v31 = 0;
do
{
v5 = v4 & 3;
v24 = v4 >> 2;
v6 = 5 - v5;
v36 = xmmword_403660;
if ( v5 < 2 )
v6 = 1 - v5;
v37 = xmmword_403620;
v7 = *((_DWORD *)&v36 + 2 * v6 + 1);
v8 = v28 + *((_DWORD *)&v36 + 2 * v6);
v9 = v29;
v10 = v29 + v7;
v25 = v8;
if ( v8 < 0 || v8 >= v3 || v10 < 0 || v10 >= v3 )// v3=0xA
{
v19 = sub_401A60(std::cout, "fail");
std::basic_ostream<char,std::char_traits<char>>::operator<<(v19, sub_401C90);
v14 = Memory;
goto LABEL_18;
}
v29 = v10;
v11 = (char *)Memory + 4 * (v9 + v28 * v3);
v12 = v10 + v8 * v3;
v4 = v24;
v13 = *((_DWORD *)Memory + v12);
*((_DWORD *)Memory + v12) = *(_DWORD *)v11;
*(_DWORD *)v11 = v13;
v28 = v25;
++v31;
}
while ( v31 < 4 );
v2 = v30-- - 1;
if ( v30 >= 0 )
continue;
break;
}
v14 = Memory;
v15 = 0;
v16 = v3 * v3;
if ( v16 <= 0 )
{
LABEL_14:
v17 = "success";
}
else
{
while ( *((_DWORD *)Memory + v15) == v15 )
{
if ( ++v15 >= v16 )
goto LABEL_14;
}
v17 = "fail";
}
v18 = sub_401A60(std::cout, v17);
std::basic_ostream<char,std::char_traits<char>>::operator<<(v18, sub_401C90);
LABEL_18:
j_j_free(v14);
if ( v34 >= 0x10 )
{
v20 = (char *)v32;
if ( v34 + 1 >= 0x1000 )
{
if ( (unsigned __int8)v32 & 0x1F )
invalid_parameter_noinfo_noreturn(v32);
v21 = *((_DWORD *)v20 - 1);
if ( v21 >= (unsigned int)v20 )
v21 = invalid_parameter_noinfo_noreturn(v20);
v22 = (unsigned int)&v20[-v21];
if ( v22 < 4 )
v21 = invalid_parameter_noinfo_noreturn(v22);
if ( v22 > 0x23 )
v21 = invalid_parameter_noinfo_noreturn(v22);
v20 = (char *)v21;
}
j_free(v20);
}
return 0;
}
三个关键字都在这里了
逐一分析这段代码功能
这里把输入的数据直接存到v32
然后调用了 sub_401300((unsigned int)&v32, (int)&v35),进去查看,发现函数名是_DWORD *__fastcall sub_401300(unsigned int input, int a2)
这时v32对应到input,v35对应a2,再往下看
这时,a2赋值到temp,input赋值到v3,
这里有个判断是否为200的地方,其实就是看输入的字符长度是否为200
再往下有个循环
这里其实就是i++,再看一下循环结束条件 while ( v14 != v15 ),往上看v14=0,再找v15,
v3=input,算来算去,v15就是200
这时可以还原出C代码:
[C] 纯文本查看 复制代码 for(i=0;i<100;i++){
temp[i]=i;
}
for(i=0;i<200;i++){
temp[i/2]=temp[i/2]*16+input[i]-65;
if((i+1)%2==1){
temp[i/2+1]=0;
}
}
注意这里有个65,也就是A,到这里可以确认的输入格式是长度为200的大写英文字母,而这个循环就是要将长度为200的输入缩合为长度为100的数据,格式就是A,A,B,B,C,C转换为00,11,22
再往下看
sub_401120((int)&v26, (int)&v35, v1); // 将堆栈数据复制到数据段
这里是保存到了数据段v26
这里可以看到一个长度为1000的数组,类似于置换表
再往下看就是关于数据置换的代码了,下面给出还原后的代码
[C] 纯文本查看 复制代码 while(1) {
n=table[i];
num=0;
do {
low = n & 3; //低三位
high = n >> 2; //高五位
j = 5 - low;
if (low < 2) {
j = 1 - low;
}
a = xmm[j * 2] + l;
b = xmm[j * 2 + 1] + k;
//printf("j=%X b=%X a=%X low=%X high=%X n=%X k=%X l=%X\n", j,b, a, low, high, n, k, l);
if (a < 0 || a >= c || b < 0 || b >= c) {
printf("fail\n");
return 0;
}
//交换
c = 0xA * l;
c += k;
d = temp[c];
//printf("c=%X temp[%d]=%X\n",c,c,d);
temp_ = temp + c;
c = 0xA * a;
c += b;
d_ = temp[c];
temp[c] = d;
//printf("c=%X temp[%d]=%X\n",c,c,d_);
*temp_ = d_;
//
l = a;
k = b;
n = high;
c = 0xA;
num++;
} while (num < 4);
//print(temp,100);
i--;
if(i<0){
break;
}
}
由于是直接按照汇编还原,代码实现比较冗长
[C] 纯文本查看 复制代码 //判断
for(i=0;i<100;i++){
if(temp[i]!=i){
printf("fail\n");
return 0;
}
}
置换后的数据与0-99比较,如果相等就成功了,否则失败
解密过程我会在附件中给出
0x03结尾
老规矩,题目和c代码会在文章最后的附件中给出,下面献上成功的截图:
附件:https://pan.baidu.com/s/1o8wvQAY 密码:i46l
版权声明:允许转载,但是一定要注明出处。
|
免费评分
-
查看全部评分
|
发帖前要善用【论坛搜索】功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。 |
|
|
|
|