CrackRTF
- 拉到IDA反编译一下,找到主函数main0,发现需要输入两次password,第一次输入的password在追加一个字符串以后还要进行一次加密操作(这里的encrypt是我自行修改的名称)
- 进入这个函数,首先发现了关键的hash操作,查一下这个函数 CryptCreateHash
文档中有
1 | BOOL CryptCreateHash( |
所以,第二个参数无符号数0x8004应当指哈希算法的类型,点击页面提供的超链 ALG_ID 可以发现这个值意味着使用的哈希算法是SHA1
- 所以基本的逻辑应该是Destination+”@DBApp”经过SHA1后得到string1
- 由于上文代码中可以确认Destination转成int之后是大于100000的,所以可以通过爆破得到Destination的值,python爆破代码如下:
1 | import hashlib |
注意,这里哈希值的字符串中的字母是默认小写的,所以upper一下和IDA中的值对应即可。最终得到Destination值为 123321
- 通过password1后还有一个password2,看一下就是输入长度为6的字符,然后追加Destination,再经过一个函数进行处理,处理函数和上文的哈希类似。
不过算法变成了MD5
- 如果 MD5(str+Destination) 结果为27019e688a4e62a649fd99cadaafdb4e,还要经过 sub_40100F函数对输入的字符串str进行判断
进入该函数,首先定位一个名为AAA的资源文件,采集文件信息并通过函数 sub_401005 这里的lpString就是前文提到的str也就是我们第二次输入的password,查看微软文档中SizeofResource和LockResource的return值可知,lpBuffer是指向资源文件第一个字节的指针,nNumberOfBytesToWrite为资源文件的字节数,进入该函数
基本的逻辑就是从AAA文件中取值与str进行循环异或,因为需要最终成功创建一个rtf文件,sub_40100F才能返回1,才能通过验证。
因为我们需要的结果字符串str(password2)只有6位,所以只需要和AAA的前六位进行异或就可以拿到RTF文件的前六位了,这里需要通过 Resource Hacker 来获取AAA前六个字节的数据
RTF文件前六位 为
{\rtf1
1 | rtf = "{\\rtf1" |
结果为 ~!3a@0
- 通过验证,自动创建dbapp.rtf文件,打开即有Flag{N0_M0re_Free_Bugs}
Youngter-drive
直接拖进IDA,符号不可见,可能是加壳了,用Exeinfo PE 查壳
UPX工具脱壳,用法参考
1 | upx -d Youngter-drive.exe |
脱壳后重新用IDA即可正常反编译
找到main函数
查阅 docs.microsoft 可知,CreateThread 函数用于在调用函数的虚拟地址空间创建一个线程,第三个参数是线程的起始地址
- 查看第一个线程的起始地址StartAddress,最终发现报栈指针错误(如果无法反编译需要按以下步骤调整栈指针)
a. 跳转到该函数地址,(直接在函数窗口搜索即可),在IDA-View可以看到
b. 为了能看到栈指针的值并做修改,需要 option->General->Disassembly->Stack pointer 勾选即可
c. 然后就发现刚才的IDA-View显示栈指针
d. 将负值修正为0即可
- 但这里不需要,因为我们已经可以反编译到源码了,其中a1根据代码上文可知是Source。
a2是后面要提到的线程2的递减指针。该函数对字符数组off_418000进行操作,该字符数组内容为 “QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasd”
基本的逻辑如果字母小于’a’或大于’z’就减去38,否则就减去96
另一个线程一直在做递减操作,不改变字符串,进程交替工作,导致奇数位字符串经过线程1的处理,偶数位字符串经过线程2不变
最后有一个判断
- off_418004字符数组的内容是 “TOiZiZtOrYaToUwPnToBsOaOapsyS” ,所以上文Source也即a1的变换后的值就是这个。
- 再回到加密函数,我们整理好逻辑为:
1 | class Solution { |
输出为ThisisthreadofwindowshahaIsES,实际上少一位,尝试得到E,flag{ThisisthreadofwindowshahaIsESE}
[ACTF新生赛2020] easyre
- 用IDA打开时,提示文件被损坏,有可能被加壳,用Exeinfo PE查看是UPX,所以用upx工具脱壳,重新拿到IDA即可
- 找到main函数
可以双击 data_start 看看数据
结合main函数代码,flag就是遍历v4从data中找打对应下标再加1
1 | class Solution { |
flag{U9X_1S_W6@T?}
[ACTF新生赛2020]rome
无壳,直接IDA反编译,找到main函数,内有关键函数 func()
可以看到首先确定了flag的格式,为ACTF{}(这里是BUU所以flag格式实际还是flag{},可以暂不考虑),另外第一个while实际上在做移位,而我们也没有必要非得逆着写代码,只要从0~127遍历字符,遇到变换后和v12中对应字符相等的就追加到flag字符串即可
1 | class Solution { |
- 得到
flag{Cae3ar_th4_Gre@t}
[GUET-CTF2019]re
- 用Exeinfo PE查壳发现UPX,upx工具脱壳,拉进IDA
- main函数如下
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
- 我根据功能对函数名进行了猜测与修改,进入加密函数后
一直到a1[31],不过缺少了a1[6],没有从其他地方找到跟a1[6]相关的数据,只能进行爆破,c++代码如下,最终结果为flag{e165421110ba03099a1c039337}
1 | class Solution { |
相册
apk文件拿到jadx反编译,搜索mail,这里调用的方法是加载了lib的
将apk文件解压,将lib中的libcore.so文件拖到IDA64查看字符串,发现几个base64编码
- 解码MTgyMTg0NjUxMjVAMTYzLmNvbQ==时,有18218465125@163.com,这就是flag
[BJDCTF2020]easy
- 拉到IDA,没有找打main函数中有什么关键信息,最后有个ques函数比较可疑,没有被调用过,其地址为0x401520
- 拖进OD,step over (F8) 到jmp指令处,双击地址将其地址改为ques的地址
- F9运行得到
- 所以flag{HACKIT4FUN}
[ACTF新生赛2020]usualCrypt
输入字符串后,首先对字符串进行Base64编码(这里的base是人为修改的,因为进入该函数能发现明显的Base64特征)。然后判断结果是否与byte_40E0E4相等
结果字符串数组为zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9,注意前面还有个7Ah
- 另外,这个base函数中有两处修改
- 第一次修改为:交换byte_40E0AA和byte_40E0A0两个数组[6,15)处的值
容易得到交换结果为 ABCDEFQRSTUVWXYPGHIJKLMNOZabcdefghijklmnopqrstuvwxyz0123456789+/ 这就是修改后的编码表
第二次修改为
是小写就减32,大写就加32,大小写字母ASCII差值为32,所以逻辑就是大小写转换。 变表Base64解码 参考 解密代码如下
1 | import base64 |
- 结果为flag{bAse64_h2s_a_Surprise}
[MRCTF2020]Transform
- main函数如下,首先输入字符串,可以推断其长度为33,原始字符串数组先用40F040做索引生成新数组再,与40F040进行异或需要与40F0E0相等
40F040及40F0E0处的数据情况如下,两者异或再索引回原来的值即为flag,后者可以用hex视图复制
解题代码为
1 | class Solution { |
- 结果为 MRCTF{Tr4nsp0sltiON_Clp93r_1s_3z}
[WUSTCTF2020]level1
- 题目给了一个二进制文件,一个文本文件,将二进制文件拖入IDA,进入main函数
- 所以逻辑很简单,就是将输入的flag,按奇偶数位对原始字符进行修改,解题代码如下
1 |
|
- 输出为 ctf2020{d9-dE6-20c}
[WUSTCTF2020]level2
exeinfo PE查到UPX壳,用UPX工具脱壳后拿到IDA
找到main函数,IDA-View有
- wctf2020{Justupx-d}
[GWCTF 2019]xxor
- 找到main函数
- 参考
- 这里dword_601078是取了每个v6元素四个字节中的后两个字节中的值,dword_60107c则是取了每个v6元素四个字节中前两个字节的值
- 为什么dword——601078那一条语句没有lodword函数却依然和有lodword函数的结果相同,这是由于dword_601078这个变量只能存储2个字节的数据,因此在读取v6[j]时只能读取其前两个字节,那么效果其实就跟lodword一样了
- sub_400686中对输入的数据两个两个一组进行异或加密
- 最后判断
- a2的值为2,2,3,4
- 解题代码如下
1 | class Solution { |
- 要注意防止溢出,原来IDA中可获取的变量类型尽量不变,否则,输出的结果会因为变量类型来得到非期望的值
- 输出为 666c61677b72655f69735f6772656174217d,转ASCII结果为 flag{re_is_great!}
[HDCTF2019]Maze
- 查壳发现UPX,脱壳后拿到IDA分析
- 找到start,发现main函数不能反编译
- jnz到下一行代码,相当于没做跳转。另外call调用的地址找不到,可以推断出这段代码添加了花指令。
- 利用OD将jnz这段指令nop掉
OD nop指令
- 原有代码段可参照上文
- 将可执行文件拖入OD,找到对应地址。双击将其用nop填充
- 修改后如下图
- 这里需要注意,此处在内存中的修改不会自动保存到可执行文件中,需要右键,将修改保存到可执行文件
- 右键弹出的窗口,并保存到文件,这时就可以发现,保存的文件是exe
- 将新文件拖入IDA,发现修改完成
- [续前节]不过这里的main函数还是不能反编译。后面这个call指令,不能全部nop,因为后面那个东西可能是有效代码。D键将其先转换为字节数据
- 先将第一个数据nop掉再转成代码,进行尝试。这里用OD再nop掉 db E8 ,方法相同,再保存到可执行文件重新用IDA打开
- 发现IDA自动将OD修改完的数据转成代码,main函数可以正常反编译了
- 查看8078和807C两个变量,发现其值分别为7和0,看到了上面的迷宫。所以adsw分别代表左右下上,8078代表行,807C代表列。
1 | *******+** |
- 可以整理到7行10列的迷宫,走法为ssaaasaassdddw,正好14步,符合main中for循环的设定,所以 flag{ssaaasaassdddw}
[BJDCTF2020]BJD hamburger competition
- 是一个unity做的游戏,这里直接用 dnspy Github地址 dnspy Github加速站地址 下载dnspy的release版本,看源码
- 在BJD hamburger competition_Data\Managed文件夹中找到Assembly-CSharp.dll,这是程序的源码。将其拖入dnspy中
- 搜索字符串CTF,找到关键的类
- 发现只要str的sha1值等于 DD01903921EA24941C26A48F2CEC24E0BB0E8CC7 就满足条件,最后的flag就是str的MD5值,先将SHA1值拿到 SHA1解密 得到1001,再生成1001的MD5得到 b8c37e33defde51cf91e1e03e51657da,但是提交不通过。进入MD5函数查看
- X2转大写,Substring取前20位,所以
1 | s= 'b8c37e33defde51cf91e1e03e51657da'.upper()[0:20] |
- 结果为B8C37E33DEFDE51CF91E,所以flag{B8C37E33DEFDE51CF91E}