【NSSCTF】jump_by_jump_revenge
收获
处理 JUMPOUT 花指令
正向爆破时,如果同时遇到两个未知变量的处理方法
本题对于条件Str1[i] = (Str1[i] + Str1[(i * i + 123) % 21]) % 96 + 32
无法进行常规的正向爆破
思路
将程序拖入 32位 IDA,查看 main 函数
对 main 函数 F5 反编译后 JUMPOUT
在 IDA View-A 中定位 main
在 main 中未发现花指令,根据 jmp _main_0
跟进到 main_0
的位置
在 main_0 中 jmp short loc_4118D2
后,到 loc_4118D2 中 jnz short near ptr loc_4118DA+2
跳转到 loc_4118DA
而 loc_4118DA 中 jmp near ptr 0C086A4CCh
跳转到无效的地址使得 main 无法被 IDA 正确编译
选中 jmp near ptr 0C086A4CCh
,使用快捷键 D 转换为硬指令:
选中 db 0E9h
,右键 -> Patching -> Change byte,将开头的 E9 改为 90
选中 db 90h
,按快捷键 C 将硬指令转换为代码
在 main_0 函数起始处按快捷键 P,重新生成函数
此时 main 函数已经被成功修复:
进入 main_0 函数:
根据条件 j_strcmp(Str1, "~4G~M:=WV7iX,zlViGmu4?hJ0H-Q*")
可以判断,还原后的 Str1 就是 flag
① 这里采用了余数的特点:Str1[i] = Str1[i] % 96 + Str1[(i * i + 123) % 21] + 32
或Str1[i] = Str1[i] % 96 + Str1[(i * i + 123) % 21] - n * 96 + 32
② 变换得到刚开始未处理过的 Str1[i]
取余后的结果,即:Str1[i] % 96 = Str1[i] - 32 - Str1[(i * i + 123) % 21]
或Str1[i] % 96 - n * 96 = Str1[i] - 32 - Str1[(i * i + 123) % 21]
③ 要得到初始的 Str1[i]
的值,只需将 Str1[i] % 96
或 Str1[i] % 96 - n * 96
的结果加上 n 个 96,如果加上 n 个 96 后的结果在 32 ~ 127 范围内,那么这个结果就是初始的 Str1[i]
的值
即:只需要将 Str1[i] - 32 - Str1[(i * i + 123) % 21]
的结果加上 n 个 96 即可,取位于 32 ~ 127 之中的结果
脚本
#include <iostream>
#include <string.h>
using namespace std;
int main(){
string Str1 = "~4G~M:=WV7iX,zlViGmu4?hJ0H-Q*";
for (int i = 28; i >= 0; --i ){
Str1[i] = Str1[i] - 32 - Str1[(i * i + 123) % 21];
if (Str1[i] < 32 || Str1[i] > 126){
for (int j = 0; j < 5; ++j) {
Str1[i] += j * 96;
if(Str1[i] >= 32 && Str1[i] <= 126)
break;
}
}
}
for (int i = 0; i < 29; ++i) {
printf("%c",Str1[i]);
}
return 0;
}
结果
NSSCTF{Jump_b9_jump!_r3V3n9e}