逆向工程 Easy_Keygen 用户名&序列号题目(超详细)wp

附上下载链接Easy_Keygen.exe
PS:本道题目已经给出了序列号 5B134977135E7D13 求用户名

下载成功后打开发现是让输入用户名和序列号的@(。・o・)@
这里写图片描述

这样输入肯定是进不去的( ´_ゝ`)✎
随便测试一下 发现若不正确会自动关闭这个小窗口
于是我们使用工具 IDA!!

IDA下载链接:https://pan.baidu.com/s/1eMHUeAE_eHb_Wbj0tagmAw 密码:vezr

PS:我安装的IDA7.0的时候出现了如下图的问题这里写图片描述
后来问过学长之后发现是安装路径错误 只要安装到C盘user下就可以啦【开熏

用IDA 打开之后 貌似要分析代码了ԅ(¯﹃¯ԅ)
摁下键盘上的F5键 得到了伪代码【厉害哇 莫名鸡冻】
这里写图片描述

int __cdecl main(int argc, const char **argv, const char **envp)
{
signed int v3; // ebp
signed int i; // esi
char v6; // [esp+Ch] [ebp-130h] // 寄存器 h代表16进制数 C是16进制的12
char v7; // [esp+Dh] [ebp-12Fh] //Dh
char v8; // [esp+Eh] [ebp-12Eh] //Eh..说明v6-v8三个应该是一个含有三个的数组
char v9; // [esp+10h] [ebp-12Ch]
char v10; // [esp+11h] [ebp-12Bh]
__int16 v11; // [esp+71h] [ebp-CBh]
char v12; // [esp+73h] [ebp-C9h] //73h
char v13; // [esp+74h] [ebp-C8h] //74h
char v14; // [esp+75h] [ebp-C7h] //75h 说明v12-v14是一个含有三个数的数组
__int16 v15; // [esp+139h] [ebp-3h]
char v16; // [esp+13Bh] [ebp-1h]
v9 = 0;
v13 = 0;
memset(&v10, 0, 0x60u); //清空数组 全都清为0
//memset()函数原型是extern void *memset(void *buffer, int c, int count) buffer:为指针或是数组,c:是赋给buffer的值,count:是buffer的长度.
v11 = 0;
v12 = 0;
memset(&v14, 0, 0xC4u);
v15 = 0;
v16 = 0;
v6 = 16;
v7 = 32;
v8 = 48;
sub_4011B9(aInputName); //调用姓名函数
scanf(aS, &v9); //输入姓名
v3 = 0;
for ( i = 0; v3 < (signed int)strlen(&v9); ++i ) //0->整个姓名长度
{
 if ( i >= 3 )
  i = 0; //i只为0,1,2
 sprintf(&v13, aS02x, &v13, (&v9 + v3++) ^ (&v6 + i));
//^是异或 为二进制的01数列 相同为0 相反为1 把最后的整个结果存放在v13的数组里
}
memset(&v9, 0, 0x64u);
sub_4011B9(aInputSerial);
scanf(aS, &v9); //输入aS 存放在v9的地址上
if ( !strcmp(&v9, &v13) ) //strcmp是对比函数 来判断姓名和刚刚的序列号是否符合
 sub_4011B9(aCorrect);
else
 sub_4011B9(aWrong);
return 0;
}

大致观察完整个代码之后
重要的是看懂下面这个循环

for ( i = 0; v3 < (signed int)strlen(&v9); ++i )
{
 if ( i >= 3 )
  i = 0;
 sprintf(&v13, aS02x, &v13, (&v9 + v3++) ^ (&v6 + i));
}

再使用OllyDbg打开【附上使用方法】

F2:设置断点,只要在光标定位的位置按F2键即可,在按一次F2键则会删除断点。
F8:单步步过,每按一次这个键执行一条反汇编窗口中的一条指令,遇到call等子程序不进入其代码。
F7:单步步入:功能同单步步过(F8)类似,区别是遇到call等子程序会进入其中,进入后首先会停留在子程序的第一条指令上。
F4:运行到选定位置,作用就是直接运行到光标所在位置处暂停。
F9:运行,按下这个键如果没有设置相应断点的话,被调试的程序将直接开始运行。
ctrl+F9:执行到返回,此命令在执行到一个ret(返回指令)指令时暂停,常用于从系统部分返回到我们调试的程序部分。
alt+F9:执行到用户代码,可用于从系统部分快速返回到我们调试的程序部分。

断点是调试器的一个重要功能,它能使程序中断在需要的地方,从而方便对其分析,常用的断点是INT3,其原理是ollydbg将断点处的代码设置为int3指令。

将光标移动到要设置断点的行,按F2键就可以设置了,也可以双击hex数据列。

设置断点可以让软件运行的时候停在设置断点的地方,以方便反复跟踪调试,当程序关闭时,ollydbg会将设置好的断点保存在UDD文件中,下次运行时还有效。

<code>这里写图片描述</code>

右击->中文引擎搜索->智能搜索
这里写图片描述

先在Input Name: 这里设置个断点
按F9直接运行到断点
然后再单步调试 F7F8F8F8………..(.. )…
到了这一步 按不动了
这里写图片描述

扫描二维码关注公众号,回复: 3116351 查看本文章

于是我们打开程序 随意输入一个字符串
这里写图片描述

然后继续F7向下单步运行
这里写图片描述

发现已经有Leo显示了出来
然后继续向下F7…
发现L e o已经一个一个出来了
这里写图片描述

4C=(‘L’)
这里写图片描述

65=(‘e’)
这里写图片描述

6F=(‘o’)

什么意思呢 我们打开ASCII表
这里写图片描述

发现L的十进制是76 转化为16进制就是4Cヾ(●゜ⅴ゜)ノ

这里写图片描述

相同的 e 和o也是
由此说明用户名都变成了16进制储存(ρ_・).。
结合算法 反向推理 写出脚本

一:

serial=[]
serial11 = “5B134977135E7D13”
for i in serial11.decode(“hex”): #十六进制默认两位两位循环
 print(i) #辅助
 serial.append(ord(i))
name = []
v6 = [16, 32, 48]
i = 0
for v3 in range(len(serial)):
 if (i >= 3):
  i= 0
 name.append(serial[v3] ^ v6[i])
 i = i+1
print(name)
namestr = “”
for j in range(len(name)):
 namestr += chr(name[j])
print(namestr)

二:

serial = “5B134977135E7D13”
b = [0x10, 0x20, 0x30] #0x10->16 0x20->32 0x30->48
a = 0
ss = ”
for i in range(0, len(serial), 2):
 print(hex(int(serial[i:i + 2], 16))) #辅助
 ss += chr(int(serial[i:i + 2], 16) ^ b[a]) #从i到第i+2位
# int() 方法的语法
#class int(x, base=10)
#参数 x – 字符串或数字。base – 进制数,默认十进制。
 a += 1
 if (a >= 3):
  a = 0
print(ss)

最后运行出结果(◆゜∀゜)b
这里写图片描述

猜你喜欢

转载自blog.csdn.net/Retrovich/article/details/82557449