DX后台截图

这个技术点真是让我煞费苦心

终于有所突破

没写完Mark

MyDll.cpp
// MyDll.cpp : 定义 DLL 的初始化例程。
//

#include "stdafx.h"
#include "MyDll.h"
#include "D3dx9tex.h"
HRESULT MyD3DXSaveSurfaceToFile(
    _In_       LPCTSTR              pDestFile,
    _In_       D3DXIMAGE_FILEFORMAT DestFormat,
    _In_       LPDIRECT3DSURFACE9   pSrcSurface,
    _In_ const PALETTEENTRY         *pSrcPalette,
    _In_ const RECT                 *pSrcRect
    );
typedef HRESULT(WINAPI* DXSave)(
    _In_       LPCTSTR              pDestFile,
    _In_       D3DXIMAGE_FILEFORMAT DestFormat,
    _In_       LPDIRECT3DSURFACE9   pSrcSurface,
    _In_ const PALETTEENTRY         *pSrcPalette,
    _In_ const RECT                 *pSrcRect
    );
DXSave OldMsgBoxW = NULL;//指向原函数的指针
FARPROC pfOldMsgBoxW;  //指向函数的远指针
BYTE OldCode[5]; //原系统API入口代码
BYTE NewCode[5]; //原系统API新的入口代码 (jmp xxxxxxxx)
HANDLE hProcess = NULL;//本程序进程句柄
HINSTANCE hInst = NULL;//API所在的dll文件句柄
void HookOn();
void HookOff();
void GetApiEntrance();
void OnBnClickedBtnStartHook();
void OnBnClickedBtnCallMsgBox();
void OnBnClickedBtnStopHook();
void capture();
#ifdef _DEBUG
#define new DEBUG_NEW
#endif

//
//TODO:  如果此 DLL 相对于 MFC DLL 是动态链接的,
//      则从此 DLL 导出的任何调入
//      MFC 的函数必须将 AFX_MANAGE_STATE 宏添加到
//      该函数的最前面。
//
//      例如: 
//
//      extern "C" BOOL PASCAL EXPORT ExportedFunction()
//      {
//          AFX_MANAGE_STATE(AfxGetStaticModuleState());
//          // 此处为普通函数体
//      }
//
//      此宏先于任何 MFC 调用
//      出现在每个函数中十分重要。  这意味着
//      它必须作为函数中的第一个语句
//      出现,甚至先于所有对象变量声明,
//      这是因为它们的构造函数可能生成 MFC
//      DLL 调用。
//
//      有关其他详细信息,
//      请参阅 MFC 技术说明 33 和 58。
//
// CMyDllApp

BEGIN_MESSAGE_MAP(CMyDllApp, CWinApp)
END_MESSAGE_MAP()
// CMyDllApp 构造
CMyDllApp theApp;
// CMyDllApp 初始化
BOOL CMyDllApp::InitInstance()
{
    CWinApp::InitInstance();
    return TRUE;
}


CMyDllApp::CMyDllApp()
{
    capture();
}

void capture(){
    DWORD dwPid = ::GetCurrentProcessId();
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, dwPid);
    GetApiEntrance();
}

void GetApiEntrance()
{
    HMODULE hmod = ::LoadLibrary(_T("d3d9.dll"));

    OldMsgBoxW = (DXSave)::GetProcAddress(hmod, "D3DXSaveSurfaceToFile");
    pfOldMsgBoxW = (FARPROC)OldMsgBoxW;

    if (pfOldMsgBoxW == NULL)
    {
        MessageBox(NULL, _T("获取原API入口地址出错"), _T("error!"), 0);
        return;
    }

    _asm
    {
        lea edi, OldCode        //获取OldCode数组的地址,放到edi
            mov esi, pfOldMsgBoxW //获取原API入口地址,放到esi
            cld   //方向标志位,为以下两条指令做准备
            movsd //复制原API入口前4个字节到OldCode数组
            movsb //复制原API入口第5个字节到OldCode数组
    }
    NewCode[0] = 0xe9;//实际上0xe9就相当于jmp指令
    _asm
    {
        lea eax, MyD3DXSaveSurfaceToFile //获取我们的MyMessageBoxW函数地址
            mov ebx, pfOldMsgBoxW  //原系统API函数地址
            sub eax, ebx             //int nAddr= UserFunAddr – SysFunAddr
            sub eax, 5           //nAddr=nAddr-5
            mov dword ptr[NewCode + 1], eax //将算出的地址nAddr保存到NewCode后面4个字节
            //注:一个函数地址占4个字节
    }

    HookOn();
}

//开启钩子的函数
void HookOn()
{
    ASSERT(hProcess != NULL);

    DWORD dwTemp = 0;
    DWORD dwOldProtect;

    //修改API函数入口前5个字节为jmp xxxxxx
    VirtualProtectEx(hProcess, pfOldMsgBoxW, 5, PAGE_READWRITE, &dwOldProtect);
    WriteProcessMemory(hProcess, pfOldMsgBoxW, NewCode, 5, 0);
    VirtualProtectEx(hProcess, pfOldMsgBoxW, 5, dwOldProtect, &dwTemp);

}

//关闭钩子的函数
void HookOff()
{
    ASSERT(hProcess != NULL);

    DWORD dwTemp = 0;
    DWORD dwOldProtect;

    //恢复API函数入口前5个字节
    VirtualProtectEx(hProcess, pfOldMsgBoxW, 5, PAGE_READWRITE, &dwOldProtect);
    WriteProcessMemory(hProcess, pfOldMsgBoxW, OldCode, 5, 0);
    VirtualProtectEx(hProcess, pfOldMsgBoxW, 5, dwOldProtect, &dwTemp);
}

HRESULT MyD3DXSaveSurfaceToFile(
    _In_       LPCTSTR              pDestFile,
    _In_       D3DXIMAGE_FILEFORMAT DestFormat,
    _In_       LPDIRECT3DSURFACE9   pSrcSurface,
    _In_ const PALETTEENTRY         *pSrcPalette,
    _In_ const RECT                 *pSrcRect
    )
{
    HookOff();//调用原函数之前,记得先恢复HOOK呀,不然是调用不到的
    //如果不恢复HOOK,就调用原函数,会造成死循环
    ::MessageBoxW(NULL,L"123",L"123",0);
    //毕竟调用的还是我们的函数,从而造成堆栈溢出,程序崩溃。
    HookOn();//调用完原函数后,记得继续开启HOOK,不然下次会HOOK不到。 
    return 0;
}
inject.cpp
#include "stdafx.h"
#include "Remote injection.h"
#include "tlhelp32.h"
using namespace std;
extern DWORD ListProcess(CString Name);
extern int EnableDebugPriv(const WCHAR *);

int _tmain(int argc, TCHAR *argv[], TCHAR *env[])
{
    //为了成功使用CreateRemoteThread()函数,必须:
    //1.利用OpenProcess()获得远程进程的句柄
    //2.利用VirtualAllocEx(),WriteProcessMemory()写入DLL路径字符串
    //3.获得远程进程中LoadLibrary()的确切地址

    //输入进程ID获得进程句柄
    DWORD dwRemoteProcessId;
    if (argc == 2)
    {
        dwRemoteProcessId = ListProcess(argv[1]);
    }
    else{
        printf("参数缺少要注入的进程名!\n");
        return 0;
    }

    //如果输入“”表示向自身进程注入
    if (dwRemoteProcessId == 0)
        dwRemoteProcessId = GetCurrentProcessId();

    //获得调试权限
    if (EnableDebugPriv(SE_DEBUG_NAME))
    {
        printf("Add Privilege error\n");
        return -1;
    }
    //调用OpenProcess()获得句柄
    HANDLE hRemoteProcess;
    if ((hRemoteProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwRemoteProcessId)) == NULL)
    {
        printf("OpenProcess error\n");
        printf("Error Code:%d\n", GetLastError());
        system("pause");
        return -2;
    }

    //在远程进程中分配内存,准备拷入DLL路径字符串
    //取得当前DLL路径
    char DllPath[260]; //Windows路径最大为
    GetCurrentDirectoryA(260, DllPath);  //获取当前进程执行目录
    printf("Proces***e Directory is %s\n", DllPath);
    strcat(DllPath, "\\..\\Debug\\MyDLL.dll"); //链接到DLL路径
    LPVOID pRemoteDllPath = VirtualAllocEx(hRemoteProcess, NULL, strlen(DllPath) + 1, MEM_COMMIT, PAGE_READWRITE);
    if (pRemoteDllPath == NULL)
    {
        printf("VirtualAllocEx error\n");
        return -3;
    }

    //向远程进程空间中写入DLL路径字符串
    printf("DllPath is %s\n", DllPath);
    SIZE_T Size;
    if (WriteProcessMemory(hRemoteProcess, pRemoteDllPath, DllPath, strlen(DllPath) + 1, &Size) == NULL)
    {
        printf("WriteProcessMemory error\n");
        return -4;
    }
    printf("WriteRrmoyrProcess Size is %d\n\n", Size);

    //获得远程进程中LoadLibrary()的地址
    HMODULE hModule = GetModuleHandle(TEXT("kernel32.dll"));
    printf("kernel32 Address : 0x%x\n\n", hModule);
    LPTHREAD_START_ROUTINE pLoadLibrary = (LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "LoadLibraryA");
    if (pLoadLibrary == NULL)
    {
        printf("GetProcAddress error\n");
        return -5;
    }
    else
    {
        printf("LoadLibrary's Address is 0x%x\n\n", pLoadLibrary);
    }

    //启动远程线程
    DWORD dwThreadId;
    HANDLE hThread;
    hThread = CreateRemoteThread(hRemoteProcess, NULL, 0, pLoadLibrary, pRemoteDllPath, 0, &dwThreadId);
    if (hThread == NULL)
    {
        printf("CreateRemoteThread error\n");
        return -6;
    }
    else
    {
        WaitForSingleObject(hThread, INFINITE);
        printf("dwThreadId is %d\n\n", dwThreadId);
        printf("Inject is done\n");
    }

    //释放分配内存
    if (VirtualFreeEx(hRemoteProcess, pRemoteDllPath, 0, MEM_RELEASE) == 0)
    {
        printf("VitualFreeEx error\n");
        return -8;
    }

    //释放句柄
    if (hThread != NULL) CloseHandle(hThread);
    if (hRemoteProcess != NULL) CloseHandle(hRemoteProcess);

    system("pause");
    return 0;
}

DWORD ListProcess(CString Name)
{
    //获取系统快照
    HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); //不要写错CreateToolhelp32Snapshot()
    if (hProcessSnap == INVALID_HANDLE_VALUE)
    {
        printf("CreateToolHelp32Snapshot error!\n");
        return -1;
    }

    //创建单个进程快照结构体,初始化大小
    PROCESSENTRY32 pe32;
    pe32.dwSize = sizeof(PROCESSENTRY32);  //务必提前初始化,否则默认的大小不一定满足要求

    //初始化缓冲区
    WCHAR buff[1024] = { 0 }; //PROCESSENTRY32中的szExeFile为WCHAR类型数组,此处应一致,使用Unicode码

    //枚举系统快照链表中的第一个进程项目
    BOOL bProcess = Process32First(hProcessSnap, &pe32);
    while (bProcess)
    {

        //格式化进程名和进程ID,这里要使用printf的宽字符版
        //格式字符串“”都需要用L转换为宽字符形式
        if (pe32.szExeFile == Name){
            wsprintf(buff, L"FileName:%-30sID:%-6d\r\n", pe32.szExeFile, pe32.th32ProcessID);
            wprintf(L"%s\n", buff);
            return pe32.th32ProcessID;
        }
        //缓冲区复位
        memset(buff, 0, sizeof(buff));
        //继续枚举下一个进程
        bProcess = Process32Next(hProcessSnap, &pe32);
    }

    CloseHandle(hProcessSnap);
    return 0;
}

int EnableDebugPriv(const WCHAR *name)
{
    HANDLE hToken;   //进程令牌句柄
    TOKEN_PRIVILEGES tp;  //TOKEN_PRIVILEGES结构体,其中包含一个【类型+操作】的权限数组
    LUID luid;       //上述结构体中的类型值

    //打开进程令牌环
    //GetCurrentProcess()获取当前进程的伪句柄,只会指向当前进程或者线程句柄,随时变化
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
    {
        printf("OpenProcessToken error\n");
        return -8;
    }

    //获得本地进程name所代表的权限类型的局部唯一ID
    if (!LookupPrivilegeValue(NULL, name, &luid))
    {
        printf("LookupPrivilegeValue error\n");
    }

    tp.PrivilegeCount = 1;    //权限数组中只有一个“元素”
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;  //权限操作
    tp.Privileges[0].Luid = luid;   //权限类型

    //调整进程权限
    if (!AdjustTokenPrivileges(hToken, 0, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
    {
        printf("AdjustTokenPrivileges error!\n");
        return -9;
    }

    return 0;
}
  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值