首页
社区
课程
招聘
[原创] [Windows驱动开发] 01_内存读取
2019-5-21 19:15 19219

[原创] [Windows驱动开发] 01_内存读取

2019-5-21 19:15
19219

图片描述

01_内存读取

经常遇到一些软件被保护起来,无法读取其内存数据,今天将基于开源库BlackBone,编写一个简单的内存读写工具。

课程目标

  • 编写工具,实现内存读写
  • BlackBone库的集成
  • 比较常见内存读取的方式

准备工作

  • 32位应用程序(开发的目标程序是32位的,所以暂时只支持32位)
  • win7-x64虚拟机
  • VS2017(10.0.17763.1)
  • 无签名驱动加载工具(win64udl_exe.exe)

功能描述

这里写了个工具,界面如下图所示:

 

九分工具箱-主界面

 

主要功能:

  • 工具启动的时候会填充进程列表Combo控件
  • 点击进程列表Combo控件,会更新进程列表
  • 进程列表中的项格式为:[pid][进程类型:x86/x64] 进程全路径
  • 选中进程,更新控件地址(0x)对应的地址内容
  • 设置读取方式:ReadProcessMemory、BlackBone_R3、BlackBone_R0
  • 读取并以16进制显示内存内容

工具会根据“读取方式”,分别执行Windows API、BlackBone API、BlackBone驱动三种方式的内存读取,满足不同的使用场景。

内存读取-BlackBone库的集成

本工具工程github代码地址:https://github.com/ninecents/MyOpen

 

本工具工程代码上传了BlackBone的VS2017版本的代码,地址为https://github.com/ninecents/MyOpen/third/Blackbone

 

本工具工程代码地址为https://github.com/ninecents/MyOpen/course/WinDriver/tools/tools.sln

 

不了解BlackBone的,可以参考BlackBone介绍

 

驱动环境搭建可参考 [Windows驱动开发] 00_环境搭建

 

集成步骤:

  • 打开工程BlackBone.sln和BlackBoneDrv.sln并编译,可以获得相应的库文件和驱动文件。这里编译选项选择Debug(XP)的,用来支持XP系统。
  • tools-MFC工程中“C/C++ -> 命令行”,添加Blackbone路径/I"../../../../third/Blackbone/src"

  • 代码中引用相关头文件,如下所示:

#include <BlackBone/Config.h>
#include <BlackBone/Process/Process.h>
#include <BlackBone/Process/MultPtr.hpp>
#include <BlackBone/Process/RPC/RemoteFunction.hpp>
#include <BlackBone/PE/PEImage.h>
#include <BlackBone/Misc/Utils.h>
#include <BlackBone/Misc/DynImport.h>
#include <BlackBone/Syscalls/Syscall.h>
#include <BlackBone/Patterns/PatternSearch.h>
#include <BlackBone/Asm/LDasm.h>
#include <BlackBone/localHook/VTableHook.hpp>
#include <BlackBone/DriverControl/DriverControl.h>

#ifdef _DEBUG
#pragma comment(lib, "../../../../third/Blackbone/build/Win32/Debug(XP)/BlackBone.lib")
#else
#pragma comment(lib, "../../../../third/Blackbone/build/Win32/Release(XP)/BlackBone.lib")
#endif
  • 调用BlackBone库函数,下面为枚举进程列表的代码
void CtoolsMFCDlg::OnCbnDropdownComboProcess()
{
    m_combo_process.ResetContent();
    blackbone::Process process;

    std::vector<DWORD> vct_pids = blackbone::Process::EnumByName(L"");
    for (auto pid : vct_pids)
    {
        NTSTATUS status = process.Attach(pid);
        CString msg;

        if (NT_SUCCESS(status))
        {
            if (process.modules().GetMainModule())
            {
                CString str_64 = process.core().isWow64() ? _T("x86") : _T("x64");
                msg.Format(_T("[%05d][%s] %s"), process.pid(), str_64.GetBuffer(), process.modules().GetMainModule()->fullPath.data());
            }
            else
            {
                msg.Format(_T("[%d] %s"), process.pid(), _T("failed_get_path"));
            }
        }
        else
        {
            msg.Format(_T("[%d] %s"), pid, _T("failed_Attach"));
        }
        m_combo_process.AddString(msg);
        int nIndex = m_combo_process.GetCount() - 1;
        m_combo_process.SetItemData(nIndex, pid);
    }
}

内存读取-检测参数

点击读取按钮,先检测参数,具体代码如下所示:

void CtoolsMFCDlg::OnBnClickedButtonRead()
{
    // 更新控件数据,清空16进制显示控件内容
    UpdateData();
    m_mem_data.SetString(_T(""));

    // 获取目标进程内存地址:ll_address
    CString str_address;
    m_mem_address.GetWindowText(str_address);
    str_address = _T("0x") + str_address;
    LONGLONG ll_address = _tcstoull_l(str_address.GetBuffer(), NULL, 16, 0);

    // 获取目标进程ID:pid
    int nIndex = m_combo_process.GetCurSel();
    DWORD pid = m_combo_process.GetItemData(nIndex);

    // 获取读取方式:str_read_type
    CString str_read_type;
    m_combo_read_type.GetWindowText(str_read_type);

    // 打开目标进程
    BlackBone::Process process;
    process.Attach(pid);
    if (!process.valid())
    {
        AfxMessageBox(_T("打开进程失败。"));
        return;
    }

    ......
}

内存读取-ReadProcessMemory

ReadProcessMemory实现很简单,直接调用该函数即可:

    SIZE_T byte_read;
    BOOL result = ReadProcessMemory(process.core().handle(), (LPCVOID)ll_address, (LPVOID)bytes, (SIZE_T)m_mem_length, &byte_read);

查看ReadProcessMemory函数原型:

WINBASEAPI
BOOL
WINAPI
WriteProcessMemory(
    __in      HANDLE hProcess,
    __in      LPVOID lpBaseAddress,
    __in_bcount(nSize) LPCVOID lpBuffer,
    __in      SIZE_T nSize,
    __out_opt SIZE_T * lpNumberOfBytesWritten
    );

参数 lpBaseAddress 的类型是LPVOID,对于32位程序,该值只有4字节,读取64位进程就只能看运气了,如果地址大于4字节,读取的结果是错的(也可能直接失败)。比如,我们读取64位的chrome进程,由于chrome.exe模块地址0x13F630000大于4字节,ReadProcessMemory显示错误的内容。

 

ReadProcessMemory方式读取结果

 

BlackBone_R3方式读取结果

内存读取-BlackBone_R3

BlackBone_R3方式实现也很简单,直接调用BlackBone的api函数即可:

NTSTATUS status = process.memory().Read(ll_address, m_mem_length, (PVOID)bytes);

BlackBone_R3方式最终调用了Nt函数NtWow64ReadVirtualMemory64(32位的Windows操作系统不知道是不是下面的调用关系),调用关系如下:

 

BlackBone_R3读取内存函数调用关系

内存读取-BlackBone_R0

BlackBone_R0方式实现如下:

// 加载驱动
NTSTATUS status = blackbone::Driver().EnsureLoaded();
// 驱动内存读取
status = blackbone::Driver().ReadMem(pid, ll_address, m_mem_length, (PVOID)bytes);

最终R3层调用了DriverControl::ReadMem函数,对应控制码是IOCTL_BLACKBONE_COPY_MEMORY。

 

而R0层调用了BBCopyMemory函数,而该函数调用了内核API函数MmCopyVirtualMemory实现内存读写。

内存读取-BlackBone_R0-测试

打开虚拟机,将win64udl_exe.exe、tools-MFC.exe、BlackBoneDrv7.sys拷贝到虚拟机中,运行win64udl_exe.exe程序(不要关闭,保证未签名的BlackBoneDrv7.sys可以正常加载):

 

虚拟机中tools需要的软件

 

打开tools-MFC.exe,选择任意进程,选择读取方式为“blackbone_R0”,点击读取按钮:运行结果如下图所示:

 

BlackBone_R0方式读取结果

内存读取-三种方式比较

读取方式 缺陷 备注
ReadProcessMemory 32位进程调用该api不能读取64位进程内存
BlackBone_R3 权限问题
BlackBone_R0 完美(稳定性、防检测)

参考文档

声明

本文章仅供用于技术研究用途,请勿利用文章内容操作用于违反法律的事情。

广而告之

欢迎各位关注公众号和QQ群进行技术交流,关注有福利喔。

 

微信公众号:

 

微信公众号

 

qq群:IT技术控/953949723

 

逐梦中原技术交流QQ群


[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

最后于 2020-3-2 21:50 被kinghzking编辑 ,原因:
收藏
点赞3
打赏
分享
最新回复 (12)
雪    币: 5734
活跃值: (1737)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
blindtiger 1 2019-5-21 19:30
2
0
你写了这么多都不如 MmCopyVirtualMemory 管用
最后于 2019-5-21 19:30 被blindtiger编辑 ,原因:
雪    币: 12837
活跃值: (8998)
能力值: ( LV9,RANK:280 )
在线值:
发帖
回帖
粉丝
hzqst 3 2019-5-21 19:30
3
0
建议学习一下山总搞的MFC界面

雪    币: 4128
活跃值: (829)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
kinghzking 2019-5-21 19:35
4
0
hzqst 建议学习一下山总搞的MFC界面
嗯,下个版本看看
雪    币: 4128
活跃值: (829)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
kinghzking 2019-5-21 19:46
5
0
小艾 你写了这么多都不如 MmCopyVirtualMemory&nbsp;管用
入门的东西,见笑了
雪    币: 1602
活跃值: (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
panti 2019-5-22 06:00
6
0
感谢楼主带领大家学习!返回太大了,每次发帖都点着
雪    币: 4128
活跃值: (829)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
kinghzking 2019-5-22 09:06
7
0
panti 感谢楼主带领大家学习!返回太大了,每次发帖都点着
我也是在学习,共勉。
雪    币: 1055
活跃值: (412)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
provence 2019-5-22 09:27
8
0
感谢分享
雪    币: 195
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
牛神说 2019-6-9 22:36
9
0
正在学习,感谢分享
雪    币: 283
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
k1649914 2019-6-17 22:33
10
0
厉害,感谢感谢
雪    币: 2782
活跃值: (2428)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
iamasbcx 2019-6-18 05:56
11
0
谢谢楼主  学习中
雪    币: 1290
活跃值: (2332)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
灵幻空间 2021-1-24 14:59
12
0
大大您这个QQ搜不到哦
雪    币: 4128
活跃值: (829)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
kinghzking 2021-1-25 11:00
13
0
灵幻空间 大大您这个QQ搜不到哦
群953949723
游客
登录 | 注册 方可回帖
返回