0x1 easy re
为了方便大家理解,我附上程序源码
1 | #include<stdio.h> |
我们现在打开吾爱破解OD,将程序拖入OD中,我们可以看到如下情况
在左上角的窗口中,右键--------中文搜索引擎------------智能搜索 具体步骤如下
我们可以查看到这个程序大部分的字符串
我们看到第二行字符串为
1 | The next chars is flag,you can use base64 to decode it! |
它告诉我们,下一个字符串就是flag,我们需要用base64解密它
1 | eGdjdGZ7V2VsY29tZV90b19YR0NURn0= //第三行字符串 |
我们将它进行base64解密即可
得到flag: xgctf{Welcome_to_XGCTF}
0x2 跳到对的地方
为了方便大家理解,我放上它的源码
1 | #include<stdio.h> |
看到了代码,我们很明显知道main函数中没有调用flag这个函数,但是我们必须要调用他,而且程序中还包含了很多垃圾字符串来误导选手,但是提示说明只要执行了代码就可以得到flag
在汇编语言中,寄存器EIP指向下一个被调用的指令,所以我们可以将EIP改变到getflag函数的头部,然后让它执行即可
接下来,我们打开OD,并导入程序,如下图
右键----------中文搜索引擎-----------智能搜索 具体操作如下
于是我们看到如下情况
我们可以从上面的源代码知道 xgctf{hdxg_ctf_ctf} 是假的flag,根据提示
1 | 地址=000919BD |
我们双击 只要代码执行这里就可以得到flag哦 这一行
就会自动跳转到对应的汇编代码
一般情况下,一个函数转为机器指令后,由于函数的调用会影响栈,所以函数的头部一般以以下汇编代码开头
1 | push ebp |
我们将EIP设置在函数头部,即 push ebp
具体操作:选中要跳转到的指令----------右键-------------设置新的EIP
注意:可能会弹出信息框询问跳转到EIP可能存在危险,点 是 即可,如以下情况
接下来只需单步(按F8一条一条执行指令)
大家会遇到一个循环,如下
对于这种循环,我们只需要在jmp指令下一条指令,右键-------断点--------运行到选定位置(F4)
此时我们回过头来看看程序是什么情况
得到flag:xgctf{Jump_And_Get_Flag}
0x3简单的XOR
首先大家要理解 A XOR B XOR B = A 的含义。
为了方便大家理解,我附上程序的源代码
1 | #include<stdio.h> |
我们将程序导入IDA
选择 下方按钮OK 即可
然后F5 反编译为伪代码
由于它是一个C++程序,而不是C语言程序,导入之后不会直接进入main函数,所以我们需要找到main函数
方法有两种,第一种就是在左侧的函数表里慢慢找,第二种方法是针对于C++程序的通用方法
双击sub_4124A0
双击sub_412120
双击sub_412140
双击 Code = sub_412410(); 的 sub_412410
双击 sub_4112B7
双击 sub_411920
1 | sub_411221(&unk_41C004); |
分析伪代码,我们通过 v7[i] = *(&v8 + i) ^ v6[i]; 可知我们输入的数据和v8-v31的数据进行异或,然后存在v7,&v8+i其实是一种数组偏移,然后后面 if ( v7[j] != v32[j] ) 可知v32和v7进行比较,我们不知道v32是什么东西。
我们可以这样思考,我们输入的字符串和另一个字符串进行异或后然后和再一个字符串进行比较,即 A XOR B == C,A是我们输入的,若假设这条式子成立,由于异或的可逆性,正确的A = C XOR B
现在我们需要找到B,带伪代码的开头我们看到如下代码
1 | v32 = "hang_dian_xin_gong_ctf!!" |
到这里静态分析完毕
我们要开始写代码直接算出正确的flag
这里我使用python语言,大家的编程语言不受限制
1 | key = [16,6,13,19,57,31,61,9,7,44,39,0,29,0,2,14,29,30,0,27,27,20,0,92] |
执行结果如下
得到flag: xgctf{This_is_easy_xor!}
其实用纯OD调试也是可以解出答案的,只需要在 v7[j] != v32[j] 的时候把v32的变量和"hang_dian_xin_gong_ctf!!"从内存中取出然后进行xor运算即可,但是汇编语言代码较多,且较为难懂,这里就不给出纯OD的解法了,但是大家可以尝试一下,这里给出的答案是最容易理解的。
0x3 多密码表
根据提示,可能存在几个序列进行调换,很可能会使用取余的方法
该程序是linux x64位程序,我们选择用ida x64 来静态分析代码
按F5进行反编译
点击v15-v9 然后按r,即可转化为字符串
这是一个有规律的序列,因为它不重复且等长
然后我们分析这一条代码
1 | for ( j = 0; j <= 18; ++j ) |
直接看中间 if ( buf[j] == ‘_’ ) v14[j] = ‘!’; 是将 _ 换为 !
我们可以改写它的if语句,但是效果不变,比如
1 | if ( buf[j] <= '@' || buf[j] > 'Z' ) else {............} |
可以改写成
1 | if(buf[j]>='A' && buf[j] <='Z') |
如法炮制,相信大家看懂了代码的意思
若这个字符若是大写就在大写的密码表(即 MNBVCXZASDFGHJKLPOIUYQWERT)里,以该字符的ascii-65作为下标读取上述密码表
若这个字符若是小写就在小写的密码表(即 qeadzcwsxryfhvntgbmlkjuiop)里,以该字符的ascii-97作为下标读取上述密码表
剩余密码表方法雷同
那么我们可以自己写个程序,顺着这个思路把 A-Z a-z 0-9 ! 输入进去,然后按照这个形式,一对一的把 9F!R9k!w3U!tM88W9Od 转化为原文
附上我C++程序
1 | #include<iostream> |
根据上面这个程序我们会得到 输入原文 加密为密文 的密码对应表
我们根据 密文 9F!R9k!w3U!tM88W9Od 一个个对应关系换成原本
换完后为 0k_y0U_G4t_Pa55w0rD ,根据题目要求加上xgctf{}
我们测试一下
得到flag: xgctf{0k_y0U_G4t_Pa55w0rD}
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 咲夜南梦's 博客!
评论