好友
阅读权限 30
听众
最后登录 1970-1-1
姚小宝
发表于 2018-10-28 17:51
本帖最后由 yechen123 于 2018-11-21 20:59 编辑
这两题目不怎么难 主要看耐心
篇幅可能有点长 可能会有错误 望见谅
先上传题目
十月份安恒杯.rar
(122.45 KB, 下载次数: 15)
没有cb的看这里
链接: https://pan.baidu.com/s/1vptBYyCO4Woyjk4mEvVu8A 提取码: eqmt
1.easytree
看题目就知道应该是考察树的知识
下载下来没exe后缀名 以为是linux文件 用winhex打开才发现是pe文件
加个exe后缀名能正常打开
查壳发现有upx壳
用吾爱脱壳 机脱壳
脱壳后用IDA 打开
两个函数 里面的代码略乱
此时打开 软件看看
ida 搜索字符串
定位关键点
附上主要代码
[Asm] 纯文本查看 复制代码
int Good_job()
{
const char *v0; // eax@4
int v2; // [sp+14h] [bp-2Ch]@1
char v3; // [sp+1Ah] [bp-26h]@4
char Str; // [sp+29h] [bp-17h]@1
int v5; // [sp+38h] [bp-8h]@4
int *v6; // [sp+3Ch] [bp-4h]@1
sub_402400();
v2 = 0;
v6 = &v2;
printHello();
gets(&Str);
if ( strlen(&Str) != 15 )
{
printf("Nah... ur a fake reverser!");
exit(0);
}
v5 = sub_401500((int)&Str, 15); // 创建结构
sub_40166E(v5, v6, (int)&v3); // v5是根节点的首地址
v0 = sub_401794(&v3); // icnerrseaetrvee
if ( !strncmp(v0, "aWNuZXJyc2VhZXRydmVl", 0x14u) )
puts("well done bro!");
printf("ur really know something about tree!");
}
else
{
printf("Nah.. ur an idiot!");
}
return 0;
}
sub_401500 sub_40166e sub_401794这几个函数比较可疑
先看看最后一个
显得有点复杂 在结合下面的代码
[Asm] 纯文本查看 复制代码
if ( !strncmp(v0, "aWNuZXJyc2VhZXRydmVl", 0x14u) )
大胆预测这是base64加密
aWNuZXJyc2VhZXRydmVl 这是密文 解密得到icnerrseaetrvee
再看看sub_401500 这个函数
看起来像是创建树结构的代码
还好这几天学完树和二叉树这一章了
大概看了下 这个代码会给每个节点创建12个字节的空间 前面四个字节储存自己的数据 中间四个字节储存左孩子的地址 最后四个字节是储存右孩子的地址
前面有限制我们只能输入15个字符 比如输入abcdefghijklmno
那么他的储存结构是这样子的(输入时候不小心换成大写了 望见谅)
再看看 sub_40166E这个函数
[Asm] 纯文本查看 复制代码
int __cdecl sub_40166E(int input, _DWORD *v6, int a3)
{
int v3; // eax@2
int result; // eax@2
if ( input )
{
v3 = (*v6)++;
*(_BYTE *)(a3 + v3) = *(_BYTE *)input;
sub_40166E(*(_DWORD *)(input + 4), v6, a3);
result = sub_40166E(*(_DWORD *)(input + 8), v6, a3);
}
return result;
}
这个大概是遍历二叉树的代码 遍历分为前序遍历 中序遍历 后序遍历 这个应该是前序遍历
好了 上面我们得到的base64解密代码是icnerrseaetrvee
那么可以根据他创建二叉树的结构 以及根据前序遍历的规则得出树结构
那么可以得到flag 为 icanreversetree
第二题 BASE++
这道题 跟九月份的有点像 有兴趣的可以看一下我前面发的九月份安恒杯月赛的帖子
说明跟base加密有关
可能改变了一下
文件给了exe和一个ida文件 直接打开ida文件
直接上代码
[Asm] 纯文本查看 复制代码
int __cdecl main(int argc, const char **argv, const char **envp)
{
int result; // eax
int v4; // [esp+30h] [ebp-28h]
int v5; // [esp+34h] [ebp-24h]
sub_401790(std::cout, "please input your flag:");
sub_4019D0(std::cin, &input_flag);
if ( (signed int)strlen((const char *)&input_flag) < 32 )// 小于32位
goto LABEL_14;
transform_1((const char *)&input_flag);
v5 = strcmp((const char *)&input_flag, "guvf_vf_n_snxr_synt_____________");
if ( v5 )
v5 = -(v5 < 0) | 1;
if ( v5 )
{
LABEL_14:
transform_2();
transform_3(strlen((const char *)&input_flag), (int)&input_flag, (int)a0);
v4 = strcmp(a0, "TRLT5amLBoLT5Z6Fa5LqN6mkTomqR66Da4LqX5mgBwkkP5wmTZ6D====");
if ( v4 )
v4 = -(v4 < 0) | 1;
if ( v4 )
sub_401790(std::cout, "soooooooooorry\n");
else
sub_401790(std::cout, "Congratulations!!!\n");
system("pause");
result = 0;
}
else
{
sub_401790(std::cout, "try harder!\n");
result = 0;
}
return result;
}
要是输入的字符串小于32 直接跳到下边的if里边
先看看if里边的东西
主要涉及函数
transform_2
transform_3
然后加密过后的字符串必须为"TRLT5amLBoLT5Z6Fa5LqN6mkTomqR66Da4LqX5mgBwkkP5wmTZ6D===="
transform_2 没啥好看的 主要生成 "NoPqRsTuVwXyZaBcDeFgHiJkLm765432"这个密码表 有兴趣对的可以看一下
看下transform_3
[Asm] 纯文本查看 复制代码
int __usercall transform_3@<eax>(int input_len@<edx>, int input_flag@<ecx>, int a3)
{
int v3; // esi
_BYTE *a0_; // edi
int input_lens; // ebx
int v7; // [esp+4h] [ebp-8h]
int input__len; // [esp+8h] [ebp-4h]
v7 = input_flag;
v3 = 0;
input__len = input_len;
if ( input_len > 0 )
{
a0_ = (_BYTE *)a3; // a0
input_lens = input_len;
do
{
base_tran_5(v3 + input_flag, input_lens, a0_);
input_flag = v7;
v3 += 5; // step 5 每次进多5步
input_lens -= 5;
a0_ += 8;
}
while ( v3 < input__len );
}
return a3;
}
主要逻辑是 每次把字符串五个字符 和总长度 和密码表传入base_tran_5 主要由这个函数加密
每次执行完 字符串长度减5
看看这个函数内部
取每个字符 经过简单的运算得到一个数值 在用这个数值当做序号取出密码表的值当做密文
最终 到了字符串末尾 看是否是8的倍数 不是就补'='补够为止
密文已经给出
那么就可以根据密文求出序号再求出明文
在这里给一下思路 该代码每次使用五个字符
比如我输入
abcdefghijklmn
那么先取abcde
在内存中就是6162636465
eax只存62636465 edx存00000061
6162636465 换成二进制就是
0110000101100010011000110110010001100101
每五个位分成一组
01100 00101 10001 00110 00110 11001 00011 00101
每一组换成十进制后当成序号取密码表中的值换成密文
比如第一组 01100 换成10进制就是12
换成密文就是Z
也就是每五个明文可以换成8个密文
知道具体原理就可以解密了
用python写脚本[Asm] 纯文本查看 复制代码
asciis = ['N', 'o', 'P', 'q', 'R', 's', 'T', 'u', 'V', 'w', 'X', 'y', 'Z', 'a', 'B', 'c', 'D', 'e', 'F', 'g', 'H', 'i', 'J', 'k', 'L', 'm', '7', '6', '5', '4', '3', '2']
encrypt = ['T', 'R', 'L', 'T', '5', 'a', 'm', 'L', 'B', 'o', 'L', 'T', '5', 'Z', '6', 'F', 'a', '5', 'L', 'q', 'N', '6', 'm', 'k', 'T', 'o', 'm', 'q', 'R', '6', '6', 'D', 'a', '4', 'L', 'q', 'X', '5', 'm', 'g', 'B', 'w', 'k', 'k', 'P', '5', 'w', 'm', 'T', 'Z', '6', 'D', '=', '=', '=', '=']
flag = [0,0,0,0,0,0,0,0]
base = [0,0,0,0,0,0,0,0]
flags = ""
flagq = ""
for i in range(0,55,8):
base[0] = i
base[1] = i + 1
base[2] = i + 2
base[3] = i + 3
base[4] = i + 4
base[5] = i + 5
base[6] = i + 6
base[7] = i + 7
flag[0] = 0
flag[1] = 0
flag[2] = 0
flag[3] = 0
flag[4] = 0
flag[5] = 0
flag[6] = 0
flag[7] = 0
for q in range(0,8):
for f in range(0,32):
if (encrypt[base[q]]==asciis[f]):
flag[q] = f
flag[0] = flag[0]<<35
flag[1] = flag[1]<<30
flag[2] = flag[2]<<25
flag[3] = flag[3]<<20
flag[4] = flag[4]<<15
flag[5] = flag[5]<<10
flag[6] = flag[6]<<5
temp = "%x"%(flag[0]+flag[1]+flag[2]+flag[3]+flag[4]+flag[5]+flag[6]+flag[7])
flags += temp
for i in range(0, len(flags), 2):
flagq += chr(int(flags[i:i+2], 16))
print flagq
得到10n78ppn3ro00o70r2opop5s3roqq937
但是 输入却不对 用od看看
经过这个函数输入的字符串被替换了 只替换小写的
用ida看看
[Asm] 纯文本查看 复制代码
signed int __thiscall transform_1(const char *this)
{
const char *input_; // edi
unsigned int v2; // esi
char v3; // cl
input_ = this;
v2 = 0;
if ( strlen(this) )
{
do
{
v3 = input_[v2];
if ( (unsigned __int8)(v3 - 97) <= 25u ) // 如果是小写
input_[v2] = (v3 - 84) % 26 + 97;
if ( (unsigned __int8)(v3 - 65) <= 25u )
input_[v2] = (v3 - 52) % 26 + 65;
++v2;
}
while ( v2 < strlen(input_) );
}
return 1;
}
因为我们输入的是小写和数字 看第一个if就行 看起来就是整个小写字符串表以为
写个代码
果然是移位
那么 刚刚我od里面看到了经过这个函数移位之后的字符串 你可以直接输入这个字符串就可以了
或者像我一样写个脚本 反正结果都是一样的
[Asm] 纯文本查看 复制代码
key = "10n78ppn3ro00o70r2opop5s3roqq937"
asciis = []
g = []
for i in range(97,123):
asciis.append(chr(((i-84)%26)+97))#生成移位之后的表
for i in range(0,32):
if (97<=ord(key[i])<=122):#小写才用改 数字就算了
temp = ord(key[i])-97
g.append(asciis[temp])
continue
g.append(key[i])
flag = ""
for i in g:
flag += i
print (flag)
得到 10a78cca3eb00b70e2bcbc5f3ebdd937
免费评分
查看全部评分