从今天开始,随着每天军训,抽空看看看雪出的0day安全这本书,将每个实验的过程记录成册。

Lab1实验内容是破解一段密码验证的C代码,编译环境VC++ 6.0,32位release版本。

  1. #include <stdio.h>
  2. #include <string.h>
  3. #define PASSWORD "1234567"
  4. int verify_password (char *password)
  5. {
  6. int authenticated;
  7. authenticated=strcmp(password,PASSWORD);
  8. return authenticated;
  9. }
  10. int main()
  11. {
  12. int valid_flag=0;
  13. char password[1024];
  14. while(1)
  15. {
  16. printf("please input password: ");
  17. scanf("%s",password);
  18. valid_flag = verify_password(password);
  19. if(valid_flag)
  20. {
  21. printf("incorrect password!\n\n");
  22. }
  23. else
  24. {
  25. printf("Congratulation! You have passed the verification!\n");
  26. break;
  27. }
  28. }
  29. }

这个小程序功能是密码验证,根据密码正确与否给出响应,运行界面如图。
1.png


Cracking

step 1: 将EXE文件拖入IDA

文件拖入ida后,ida会自动识别main函数,并用流程图的形式标注出函数内部的跳转指令。 选中程序分支点,对应C代码中的if分支点,空格键切换到汇编指令界面。 获得程序运行时的内存地址VA:0x00401071

2.png

step 2: 用Olleydbg打开EXE文件进行动态调试

按F8单步执行,直到执行到main函数,此时按F7进入main函数。main函数有一个鲜明的特征,在调用之前会有连续三次压栈操作,为main函数传入argc,argv等参数。F7跟入main函数,再连续F8找到0x00401071。 也可以使用快捷键Ctrl+G,输入IDA得到的VA,直接跳转到分支处。

4.png

按F2在0x00401071处设置断点,按F9让程序执行。

5.png

密码验证函数返回值存在EAX寄存器中,而if()语句通过以下指令实现。 ```assembly TEST EAX,EAX JE XXXXX

;test eax,eax和 and eax,eax 语句类似,将EAX的值进行与操作,不过test不改变eax寄存器的值,只改变FLAG寄存器的状态。例如,如果eax寄存器值1h,则与结果为1,则不会跳转je xxxxx。je 是标志位为0的时候跳转,相当于else,而jne 是标志位不为0的时候跳转。 ```

可以将TEST改为XOR或者将JE指令改为JNE指令皆可以实现输入错误密码也可登陆的效果。这里我们修改JE为JNE,JE指令十六进制为74,JNE指令十六进制为75。这时双击这条指令修改为jne单机汇编按钮将其写入内存。这时候已经在内存中实现了程序破解。

6.png

step 3: 计算偏移修改二进制文件

此时我们通过LordPE软件打开.exe文件,查看PE文件的节信息,得到节偏移。 8.png

文件偏移地址=虚拟内存地址(VA) - 装载基址(Image Base) - 节偏移 =0x00401071 - 0x00400000 - 0x00 =0x1071 然后通过UE软件修改二进制文件,在PE文件中位于距离文件开始处1071字节地方。快捷键Ctrl+G输入0x1071跳转到JE指令机器代码处。修改74为75,保存后重新运行可执行文件,则完成此次程序破解,此时出入正确的密码”1234567”反而提示错误了。 9.png