Crack小实验
c编写密码验证程序
#include<stdio.h>
#define PASSWORD "1234567"
int verify_password (char *password)
{
int authenticated;
authenticated = strcmp(password,PASSWORD); //strcmp比较两个字符,若相等返回0
return authenticated;
}
int main()
{
int valid_flag = 0;
char password[1024];
while(1)
{
printf("please input password: ");
scanf("%s",password);
valid_flag = verify_password(password);
if(valid_flag)
{
printf("incorrect password!\n\n");
}
else
{
printf("Congratulation! You have passed the verification!\n\n");
break;
}
}
return 0;
}
IDA静态反汇编
-
将编译的.exe用IDA打开,IDA就会把二进制文件翻译成质量上乘的反汇编代码
-
按下空格键会显示类似函数的流程图
- 选中程序的分支点,也就是C代码的if语句,按空格键切换到汇编指令界面
- VA(虚拟内存地址)=RVA(相对虚拟地址) — Image Base(映射基址)
- 可以看到这条指令位于PE文件的.text节,VA:00401578
OllyDbg动态调式
- 注意32位或者64位的程序,要对应版本进行调式
- 将.exe文件用ollydbg打开,使用快捷键ctrl+g搜索由IDA分析出来的VA(虚拟内存地址)
- 选中这条指令按F2设置断点,成功后指令会被标记成不同颜色,按下F9让程序运行。进入程序输入错误密码,回车确认后,ollydbg会重新中断程序,收回控制权
- 密码验证函数的返回值会存在EAX寄存器中,if语句通过以下指令实现
mov [esp+41Ch], eax //将eax寄存器的值放入[esp+41Ch]内存地址中,eax32位寄存器通常存放函数返回值
cmp dword ptr [esp+41Ch], 0 //将[esp+41Ch]内存地址的双字型数据和0进行比较
je short loc_401588 //如若等于0跳转到密码确认流程,非0不跳转,执行密码重输流程
- 如果我们将je这条指令修改位jnz(非0则跳转),那么整个程序的逻辑就会放过来,输入错误的密码会被确认,输入正确的密码反而要求1重新输入,双击这条指令,修改成jnz,点击"Assembly",确认修改,写入内存。会发现原来的机器指令74变为75,jump is taken提示跳转将要发生。
LordPE
- 将.exe用LordPE打开,查看PE文件的节信息,求出跳转指令在文件的偏移地址
- 用 节的相对虚拟内存地址 减 节的文件偏移地址 得到 节偏移地址
- 计算指令偏移地址等于之前得到相对偏移地址减去映射地址(exe文件的映射地址默认是0x00400000)再减去节偏移地址
文件偏移地址 = 相对偏移地址 - 装载基址 - 节偏移地址
= 0x00401578 - 0x00400000 - (0x00001000 - 0x0000400)
= 0x978
- 计算得到这条指令在距离文件开始处的978h,用16进制编辑器进行修改
Hex Workshop
- 将.exe文件用hex wordshop打开,ctrl+g搜索978(16进制),将值74(JE)修改为75(JNZ),保存后重新运行可执行文件(可能会将.exe变成.bak文件,将.bak后缀修改为.exe运行即可)
- 运行结果如下,当输入正确密码"1234567"后,反而会被提示错误
说明
实验来自:0day安全:软件漏洞分析技术-Crack小实验