先查壳 发现为64位无壳
用ida64位打开 找到左侧的main函数并按tab转换为c语言
结果如下
分析第三行 可以知道是分配了 16 字节的内存,并将其地址赋给全局变量 qword_140004618
接着第四行将 qword_140004618
中的地址赋值给 qword_140004620
这意味着 qword_140004620
也指向了刚才分配的内存块
第五行将 qword_140004618
指向的内存块的第 8 字节开始的8字节(64 位)设置为 0
六七两行可能涉及格式化整数的操作 最后把sub_1400010E0
转换为一个 __fastcall
调用约定的函数指针,并且被立即调用 分析这个函数指针可能指向一个特定功能的实现,并且被立即执行
接下来先跟进sub_140001020
具体操作可能是v2先获取标准输出文件指针 然后调用 sub_140001000
函数 并将其结果(一个 64 位整数指针)存储在 v3
中 最后使用标准的 vfprintf
函数将格式化的数据输出到 v2 然后
_stdio_common_vfprintf
应该是用来处理格式化输出的
接着返回 再跟进sub_140001080函数
和上个函数差不多 也是用于从标准输入读取格式化数据的
再返回去跟进sub_1400010E0函数
这个函数较为复杂 看起来像是种加密?(雾) 从头开始分析 13行将 a1
转换为 64 位整数存储在 v3
中 (这里的a1是指向字符数组的指针)接着在 do-while
循环中 似乎进行了某种字符处理或变换 将 a1
中的字符基于 v3
进行某种转换 并逐步递减v3 然后32行在循环中对处理后的字符进行操作 并调用 sub_1400011E0
函数进行进一步处理 v7 ^ 7u
是一个按位异或操作 最后sub_140001220
函数被调用来执行最后的处理
既然这样 那我们就继续跟进sub_1400011E0
和 sub_140001220
函数
首先是sub_1400011E0函数
由于本人没学链表 去查了一下(手动投降ε(┬┬﹏┬┬)3)sub_1400011E0
函数应该主要是用于在内存中创建一个新的节点 并将其链接到一个全局链表或队列中 下面具体拆解一下
第六行分配了 16 字节的内存 并将其指针赋值给result 然后第七行将全局变量 qword_140004618
的当前值赋给 v3
该变量指向链表的最后一个节点 第八行将新分配的节点设置为链表的最后一个节点 然后第九行将新节点的指针存储到前一个节点的指针域中,以形成链表的链接 接着将输入的 a1
字符存储在当前节点的数据域中 最后将新节点的指针域(next指针)初始化为 0
表示链表的末尾
再回到上一步跟进sub_140001220函数
sub_140001220
函数是一个复杂的循环 它逐步遍历链表 比较每个节点的数据与某个预定义的字符串aV4pY59(也就是'..v4p$$!>Y59-' 跟进回原文即可发现) 然后根据匹配的长度采取不同的操作 如果找到特定的模式 它会调用一些其他函数 (sub_1400012E0
或 sub_1400012B0
)
根据以上分析 进一步推断 程序的主要逻辑围绕在一个链表的操作上 将输入的数据通过某种形式的编码或加密处理后存入链表中 然后依次遍历链表 与一个预定义的字符串('..v4p$$!>Y59-')进行匹配
在原文我们还可以找到此链表 也就是下图的')(*&^%489$!057@#><:2163qwe'
接着就可以根据以上分析写脚本了
运行后得到一串数字2484524302484524302 输入到对话框中发现为正确的flag