菜鸟的Win32逆向入门总结,程序、word笔记见文末!

1039 1
小菜鸟一枚 2022-3-16 20:15:02 | 显示全部楼层 |阅读模式
Win32逆向总结
1. 逆向环境搭建
1.1下载吾爱破解专用版Ollydbg:http://www.52pojie.cn/thread-350397-1-1.html
1.3其他工具见爱盘:http://down.52pojie.cn/Tools/

2. 逆向工具介绍
2.1. OllyDbg
是一种具有可视化界面的32位汇编分析调试器,是一个新的动态追踪工具,将IDA与SoftICE结合起来的思想,Ring3级调试器,非常容易上手,己代替SoftICE成为当今最为流行的调试解密工具了。同时还支持插件扩展功能,是目前最强大的调试工具。
2.2. IDA
反编译程序和调试器是一个交互式、可编程、可扩展的多处理器反编译程序,托管在Windows、Linux或Mac OS X上。IDA已成为恶意代码分析、漏洞研究和商业现成验证的事实标准。
2.3. Detect it Easy
(查壳工具)支持文件直接拖放,可添加到右键菜单,非常方便,查壳工具(DiE)是一款优秀的查壳工具。
2.4. StudyPE
■支持PE32、PE64、.net PE,提供丰富的PE分析功能。
■提供丰富的PE编辑功能。
■提供 RVA FOA 互相转换功能。
■提供 PE 反汇编及反汇编编辑、比较功能。
■提供 PE 内多种数据搜索功能。
■有限的查壳功能。
■有限的 PE 资源查看处理功能。
■有限的图片及文本格式文件查看功能。

3. 静态分析
3.1第一步将软件拖进去查壳(为什么要查壳呢?因为软件加壳后你就搜索不到字符串,也不能直接爆破了,只能脱壳,或者给程序打补丁了)
下图告诉了我们哪些信息:
1)文件类型PE32,32位程序
2)软件入口地址:004021e2
3)软件基址:401000
4)程序是用C++编写的
file:///C:\Users\LENOVO\AppData\Local\Temp\ksohtml7244\wps13.jpg

3.2第二步将软件拖进IDA分析(IDA除了反汇编代码外,还给我们提供了强大的F5功能,能生成伪代码)
下图告诉了我们哪些信息:
1)左边看到了main函数,学过c语言的都知道每个程序都有一个main函数,它是程序执行的入口点
2)但是这里对应的地址是00401210,不是查壳时显示的004021e2,我们往下拉,看到了一个start函数,对应的地址正是004021e2,其实这才是程序的启动入口点。
file:///C:\Users\LENOVO\AppData\Local\Temp\ksohtml7244\wps14.jpgfile:///C:\Users\LENOVO\AppData\Local\Temp\ksohtml7244\wps15.jpg

3.3第三步对着main函数按下F5(是不是这个代码比汇编代码看的舒服多了,这就是F5强大反编译功能)
1)接下来就是去阅读代码了
2)然而你发现看不懂,这个程序让你输入密码
3)下面却没有cout<<”请输入密码:”这样的代码
file:///C:\Users\LENOVO\AppData\Local\Temp\ksohtml7244\wps16.jpg

4. 动态调试
4.1IDA的动态调试步骤
1)下断点
2)选择调试器local windows debugger
3)点绿色三角运行
4)F8单步走调试(经过v6 = sub_401730(sub_401970);这一行代码窗口出现了提示)
file:///C:\Users\LENOVO\AppData\Local\Temp\ksohtml7244\wps17.jpg
5)继续F8,看这一行sub_401C50(std::cin, Block);卡住了,就是让我们输入数据了,存在block里面,我先输入123456,然后又可以F8继续走了。
6)如果想看数据对着变量点进去即可,也可以鼠标悬停看。

4.2OllyDbg的动态调试步骤
1)先用StudyPE打开
可以看到,文件基址是动态基址,啥叫动态基址(用OD打开程序,每次打开程序入口地址不一样,很干扰我们分析,点一下固定基址,然后保存):
010A21E2 > $  E8 FF030000   call CrackMe.010A25E6
010A21E7   .^ E9 74FEFFFF   jmp CrackMe.010A2060
013921E2 > $  E8 FF030000   call CrackMe.013925E6
013921E7   .^ E9 74FEFFFF   jmp CrackMe.01392060
file:///C:\Users\LENOVO\AppData\Local\Temp\ksohtml7244\wps18.jpg
2)将程序用OD工具打开,看这次地址就是固定的401000+入口地址21E2了。
file:///C:\Users\LENOVO\AppData\Local\Temp\ksohtml7244\wps19.jpg
3)接下来右键搜索中文字符串,各种中文提示都出来了。
file:///C:\Users\LENOVO\AppData\Local\Temp\ksohtml7244\wps20.jpg
4)双击破解成功提示字符串,跳转过去,右键断点-》切换F2。
file:///C:\Users\LENOVO\AppData\Local\Temp\ksohtml7244\wps21.jpg
5)接下来就可以改变程序跳转进行我们的爆破了。

5. Hook介绍
5.1消息HooK:
消息处理过程:
1)当按下键盘时,会产生一个键盘按下的消息,这个消息首先被加入到系统消息队列
2)操作系统从消息队列中取出消息,添加到相应的程序的消息队列中
3)程序自身通过GetMessage获取消息,DispatchMessage 分发消息,通过消息回调函数处理消息。
什么是消息HOOK:
HOOK就是从系统消息队列到应用程序消息队列之前 对消息进行处理,处理之后在扔给下一个消息钩子(HOOK)或者扔到应用程序的消息队列中。
file:///C:\Users\LENOVO\AppData\Local\Temp\ksohtml7244\wps22.jpg
&#8195;&#8195;
完成HOOK涉及到的相关API:
API名称
作用
SetWindowsHookEx
设置钩子
CallNextHookEx
将钩子信息传递到当前钩子链中的下一个子程序
UnhookWindowsHookEx
卸载钩子
&#8195;&#8195;注意:操作系统是64位生成64位的exe和dll注入,32位dll注入64位exe电脑会卡死。如果生成的是32位dll和exe,要用32位的记事本实验,可以去C:\Windows\SysWOW64下打开记事本,这个目录下都是32位的。
5.2IAT HooK(找到函数表,将目标函数替换成我们自己写的函数):
file:///C:\Users\LENOVO\AppData\Local\Temp\ksohtml7244\wps23.png
1)获取要替换函数的地址步骤(解析PE文件):
//获取进程句柄
//先找DOS头
//获取NT头
//获取可选PE头
//获取数据目录表
//获取导入表
//遍历dll,获取符合条件的函数
//找到相同的dll文件
//获取导入名称表
//获取导入地址表
//找到就返回函数的IAT
3)注入dll(可以远程线程注入,也可以使用注入工具)
5.3inline HOOK(内联hook )让正常程序执行的流程跳转到我们写好的代码中,执行完后,跳转回原始地址。
1)找到我们要Hook的函数地址
2)保存要Hook的前5个字节
3)计算目标函数距离jmp的偏移值
4)改变函数的前5个字节

6. 实战
6.1爆破
1)0040140F  |. /75 18         jnz short CrackMe.00401429
向上找到这句成功的关键跳,F2下断点,F9运行,随便输入123456提示失败,说明没有执行到这里。
2)逆向是已知结果去逆推过程,所以从失败这里入手,去段首00401490  /$  55            push ebp
下断点,F9运行,输入123456,停下来了看堆栈
0018FEE8   0040134E  返回到 CrackMe.0040134E
双击回车过去,看到call ebx间接调用
0040134C  |.  FFD3  call ebx         ;  CrackMe.00401490
向上翻一翻看到,很多地方跳到0040133E,只有运行到00401330这里,然后把4013B0正确的地址给到ebx,才会执行成功。
0040132E  |. /75 0E         jnz short CrackMe.0040133E
00401330  |. |81FB 90144000 cmp ebx,CrackMe.00401490  ;  
00401336  |. |B8 B0134000   mov eax,CrackMe.004013B0
0040133B  |. |0F45D8  cmovne ebx,eax            ;
0040133E  |> \83EC 18       sub esp,0x18
直接强行把call ebx改成call 004013B0,F2下上断点,可以看到成功执行到正确的call了,然后将一句jnz改成jmp即可爆破。
0040140F  |. /75 18         jnz short CrackMe.00401429
file:///C:\Users\LENOVO\AppData\Local\Temp\ksohtml7244\wps24.jpg
可能你觉得这只是取巧,强行改变程序执行流程,那我们接下来分析一下程序。

6.2分析
通过前面的爆破,我们知道了4013B0是正确的函数,我们再通过IDA来看代码:
LABEL_22:
      if ( !v14 && v5 != sub_401490 )
        v5 = sub_4013B0;
      goto LABEL_25;
    }
LABEL_21:
    v14 = 0;
    goto LABEL_22;
  }
LABEL_25:
  sub_401570(Block);
  ((void (*)(void))v5)();
最终调用v5,也就是call ebx,这里v5这在lable 22标签里会赋值sub_4013B0,要想到label 22,得先到lable 21,然后goto过去。
LABEL_12:
      if ( v9 == -4 )
        goto LABEL_21;
Lable 21又是从lable 12这里跳转过来的。
while ( *v8 == *(void **)v4 )
      {
        ++v8;
        v4 += 4;
        v10 = v9 < 4;
        v9 -= 4;
        if ( v10 )
          goto LABEL_12;
      }
Lable 12又是从这个while循环里跳过来的,再看v9每次循环自减4,v10是退出条件,而只有v9==-4才会按照刚才的流程执行,所以v9一定是4的倍数。
  if ( v19 == v7 )
  {
    v9 = v19 - 4;
if ( v19 < 4 )
V19必须等于v7,且大于4,然后进入才会进入while循环,我们用IDA动态调试一下,可以猜到v19就是我们输入字符串的长度,v7就是"Tb8C4k2pMV",那么我们输入的字符串就必须是10位,但是只有输入字符串是4的倍数才会进入正确call,所以这个CM有问题,无解。
看看作者的源代码:
#include<iostream>
#include<conio.h>
#include<string>
using namespace std;
void success(string);//定义函数原型
void fail(string);
int main()
{
    char* a = new char[11]{ 84,98,56,67,52,107,50,112,77,86,0 };//Tb8C4k2pMV,真·脸滚键盘
    string password;
    void(*b)(string) = NULL;
    cout << "请输入密码:" << endl;
    cin >> password;
    for (unsigned int i = 0; i < password.size(); ++i)
    {
        if (0 <= password <= 112)//突然觉得不按标准写代码比按标准的写好看
        {//全是正数,所以加个判断
            b = fail;
        }
    }
    if (password==a)
    {
        if (b != fail)
        {
            b = success;
        }
    }
    b(password);
    _getch();
    return 0;
}
void success(string password)
{
    char* a = new char[11]{ 84,98,56,67,52,107,50,112,77,86,0 };//Tb8C4k2pMV
    if (password != a)//来个暗桩
    {
        fail(password);
        return;
    }
    cout << "破解成功,感谢您的参与!" << endl;
    return;
}
void fail(string password)//
{
    cout << "破解失败,请继续加油!" << endl;
    return;
}
一时之间似乎没有发现代码有什么问题,在我怀疑的for循环那里我们打上断点看看,launch.json文件注意修改
"externalConsole": true,
运行起来,输入作者提供的密码:Tb8C4k2pMV
if (0 <= password <= 112)//突然觉得不按标准写代码比按标准的写好看
        {//全是正数,所以加个判断
            b = fail;
        }
看这里我们输入的如果在这个范围内,直接fali了
if (b != fail)
        {
            b = success;
        }
然后再看这里,b绝对是fali了。。。,然后直接跳向失败。


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2026 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行