看雪 2016 CTF 第八题 点评和解析
看雪版主&评委
netwind点评
此题是一道简单的算法题,根据字符串提示信息以及下断关键API可以定位到注册算法的位置,算法是一个数学关系式,求解便可以得到答案
出题者简介:
无名侠,目前在研究Android安全,也参加信息学奥林匹克竞赛。
下面选择了一位分析者破解pj的详细分析:
1. 发现cm 64位程序,先拖进ida 看看流程,发现很清晰。
IDA查找字符串找到可疑地方
两处字符串 一处是恭喜注册成功,一处是注册提示
进去看看,找到调用的地方,流程图有点多,我们菜鸟必备技能,F5
看到可疑算法部分
那问题来了,如何找到关键地方呢?
答:就是动态分析,为啥要动态分析呢?因为参数原因 你要看参数是什么。
要分析,你要用调试工具呀。
如何寻找x64调试工具呢?
答:找了好几个,例如:
a. windbg 没界面感觉不好用。
b. Visual DuxDebugger 这个感觉不太友好,好多功能都没有。
c. MDebug_x64 这个感觉还行。
经介绍各位导师介绍x64dbg ,拿到这个感觉,这不是od吗?
虽然和od 想比有些功能很鸡肋,但是我认为已经是众多x64调试工具里面比较好的。纯属个人观点。这段可以跳过 ,不bb了。感谢开源 感谢这个作者.
2. 有了工具 和算法关键地方 还怕什么,直接开整起来.
怎么找到ida 看到的一些可疑的地方呢?
一开始想用字节搜素定位过去,测试没成功。
那就是基址函数头偏移大法.
Ida 函数头偏移是14B0
X64dbg 找到基址 Alt+M或者视图——内存分布 基地址:000000013F4C0000
Ida函数头偏移+程序基址=000000013F4C0000+14B0
跳转这个地方,对比ida 查找正确
2.1先找到爆破点,再找算法。
单步走下去。注意跳转。下面是爆破点
跳过去就会成功 否则错误。
2.2 找到爆破地方向上分析
找到谁影响ecx eax
输入假码 123456
A678是另外一个算法 和输入相关。我们暂且不讨论这个
经过分析上面算法发现
[000000013F695CC0+c*4] 这个是固定的数值134, 已知的量
A678*2+[000000013F695CC0+c*4]=3*A678
看这个像什么 这个不是小学的解一元一次方程吗
A678设为x
2x+134=3x 解 x=134
(注意134为 16进制)
2.3 查找输入相关的算法
这个算法只要查找A678怎么来的
Ida 字符串嫌疑法 假码处理 这个就是输入处理算法
继续基址函数头偏移,定位到关键算法地方 IDA F5 动态调试也可以分析
就是这个地方
这个代码vc可以直接编译, 修改下 就可以
这个算法结果存放到v1
v1结果为 134
只有(signed int)(v1 * v1) % v3 == v2才终止循环
通过算法分析
v3=10^v6
V6是长度
测试 答案不唯一 4864 94864
具体源码如下
##include <stdio.h>
#include <iostream.h>
signed int jisuan( int a1);
int main()
{
int result=jisuan(123456);
int nxx3=(0x134*0x134)%1000;
int nxx4=(0x134*0x134)%10000;
int nxx5=(0x134*0x134)%100000;
int nxx6=(0x134*0x134)%1000000;
int nxx7=(0x134*0x134)%10000000;
int nxx8=(0x134*0x134)%100000000;
//4864 94864 答案不唯一 nxx 就是输入的注册码
return result;
}
signed int jisuan( int a1)
{
unsigned int v1; // er9@1
signed int v2; // er11@1
signed int v3; // er8@1
signed int v4; // er10@1
__int64 v6; // rax@8
v1 = 0;
v2 = a1;
v3 = 1;
v4 = 0;
if ( a1 == 874 || a1 == 987654321 )
return 0xFFFFFFFFi64;
if ( a1 )
{
do
{
++v4;
a1 /= 10;
}
while ( a1 );
if ( v4 < 1 )
goto LABEL_10;
}
else
{
v4 = 1;
}
v6 = (unsigned int)v4;
//v6 长度
do
{
v3 *= 10;
--v6;
}
while ( v6 );
// v3=10^v6
do
LABEL_10:
++v1;
while ( (signed int)(v1 * v1) % v3 != v2 );
return v1;
}
看雪安全 · 看雪众测
持续关注安全16年,专业为您服务!
快,关注这个公众号,一起涨姿势~