• x64 下记事本WriteFile() API钩取


    《逆向工程核心原理》第30章 记事本WriteFile() API钩取 

    原文是在x86下,而在x64下函数调用方式为fastcall,前4个参数保存在寄存器中。在原代码基础上进行修改:

      1 // myhookdbg.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
      2 //
      3 
      4 #include "pch.h"
      5 #include <iostream>
      6 #include <windows.h>
      7 #include <tchar.h>
      8 #include <tlhelp32.h>
      9 #include <stdio.h>
     10 #include <shlobj.h>
     11 
     12 
     13 LPVOID g_pfWriteFile = NULL;
     14 CREATE_PROCESS_DEBUG_INFO g_cpdi;
     15 BYTE g_chINT3 = 0xCC, g_chOrgByte = 0;
     16 BOOL OnCreateProcessDebugEvent(LPDEBUG_EVENT pde)
     17 {
     18     // 查找API地址
     19     HMODULE dll = GetModuleHandleA("kernel32.dll");
     20     g_pfWriteFile = GetProcAddress(dll, "WriteFile");
     21     //g_pfWriteFile =(LPVOID)0x7ffca76b2500;
     22     printf("kernel32.dll基址:%I64x
    ", dll);
     23     printf("WriteFile地址:%I64x
    ", (DWORD64 )g_pfWriteFile);
     24     // API Hook - WriteFile()
     25     //   将byte更改为0xCC (INT 3)
     26     //  orginal byte是备份
     27     memcpy(&g_cpdi, &pde->u.CreateProcessInfo, sizeof(CREATE_PROCESS_DEBUG_INFO));
     28     ReadProcessMemory(g_cpdi.hProcess, g_pfWriteFile,
     29         &g_chOrgByte, sizeof(BYTE), NULL);
     30     printf("原api调用处字节:%x
    ", g_chOrgByte);
     31     WriteProcessMemory(g_cpdi.hProcess, g_pfWriteFile,
     32         &g_chINT3, sizeof(BYTE), NULL);
     33     BYTE arr[10];
     34     ReadProcessMemory(g_cpdi.hProcess, g_pfWriteFile,
     35         arr, sizeof(BYTE)*10, NULL);
     36     printf("修改后:
    ");
     37     for (int i = 0; i < 10; i++)
     38         printf("%02x ", arr[i]);
     39     printf("
    ");
     40     return TRUE;
     41 }
     42 
     43 BOOL OnExceptionDebugEvent(LPDEBUG_EVENT pde)
     44 {
     45     CONTEXT ctx;
     46     PBYTE lpBuffer = NULL;
     47     DWORD i;
     48     ULONG_PTR dwNumOfBytesToWrite, dwAddrOfBuffer;
     49     PEXCEPTION_RECORD64 per =(PEXCEPTION_RECORD64)&pde->u.Exception.ExceptionRecord;
     50 
     51     // BreakPoint exception (INT 3) 的情况
     52     if (EXCEPTION_BREAKPOINT == per->ExceptionCode)
     53     {
     54         // 如果BP地址是WriteFile,
     55         if ((DWORD64)g_pfWriteFile == per->ExceptionAddress)
     56         {
     57             printf("发现writefile调用,地址:%I64X
    ", g_pfWriteFile);
     58             // #1. Unhook
     59             //   如果BP地址是WriteFile(用0xCC覆盖的部分返回original byte)
     60             WriteProcessMemory(g_cpdi.hProcess, g_pfWriteFile,
     61                 &g_chOrgByte, sizeof(BYTE), NULL);
     62             BYTE arr[10];
     63             ReadProcessMemory(g_cpdi.hProcess, g_pfWriteFile,
     64                 arr, sizeof(BYTE)*10, NULL);
     65             printf("恢复后:");
     66             for (int i = 0; i < 10; i++)
     67                 printf("%02x ", arr[i]);
     68             printf("
    ");
     69             // #2. 寻求Thread Context
     70             //ctx.ContextFlags = CONTEXT_CONTROL;SegSs栈段, Rsp, SegCs代码段, Rip, and EFlags
     71             ctx.ContextFlags = CONTEXT_FULL;//要获得全部寄存器
     72             GetThreadContext(g_cpdi.hThread, &ctx);
     73             LPOVERLAPPED arg5_lpOverlapped = NULL;
     74             ReadProcessMemory(g_cpdi.hProcess, (LPVOID)(ctx.Rsp + 0x28), &arg5_lpOverlapped, sizeof(DWORD), NULL);
     75             printf("寄存器数据:
    ");
     76             //printf("rax:%I64x
    ", ctx.Rax);
     77             //printf("rbx:%I64x
    ", ctx.Rbx);
     78             printf("rcx:%I64x
    ", ctx.Rcx);
     79             printf("rdx:%I64x
    ", ctx.Rdx);
     80             printf("r8:%I64x
    ", ctx.R8);
     81             printf("r9:%I64x
    ", ctx.R9);
     82             printf("arg5:%I64x
    ",arg5_lpOverlapped);
     83             
     84             
     85             // #3.获取param 2和3的值
     86             //   x86函数参数存在于此进程的栈中;x64 fastcall 前4个参数存在寄存器中
     87             //   LPCVOID lpBuffer,//数据缓存区指针 rdx 
     88             //    DWORD   nNumberOfBytesToWrite,//你要写的字节数 r8
     89             //   param 2 : rdx
     90             //   param 3 : r8
     91 
     92             //ReadProcessMemory(g_cpdi.hProcess, (LPVOID)(ctx.esp + 0x8),&dwAddrOfBuffer, sizeof(DWORD), NULL);
     93             //ReadProcessMemory(g_cpdi.hProcess, (LPVOID)(ctx.esp + 0xC),&dwNumOfBytesToWrite, sizeof(DWORD), NULL);
     94             dwAddrOfBuffer = ctx.Rdx;
     95             dwNumOfBytesToWrite = ctx.R8;
     96             //printf("%s
    ", dwAddrOfBuffer);
     97             // #4. 临时缓冲配额
     98             lpBuffer = (PBYTE)malloc(dwNumOfBytesToWrite + 1);
     99             memset(lpBuffer, 0, dwNumOfBytesToWrite + 1);
    100 
    101             // #5. 将WriteFile的缓冲复制到临时缓冲
    102             ReadProcessMemory(g_cpdi.hProcess, (LPVOID)dwAddrOfBuffer,
    103                 lpBuffer, dwNumOfBytesToWrite, NULL);
    104             printf("
    ### original string ###
    %s
    ", lpBuffer);
    105 
    106             // #6.小写->大写转换
    107             for (i = 0; i < dwNumOfBytesToWrite; i++)
    108             {
    109                 if (0x61 <= lpBuffer[i] && lpBuffer[i] <= 0x7A)
    110                     lpBuffer[i] -= 0x20;
    111             }
    112 
    113             printf("
    ### converted string ###
    %s
    ", lpBuffer);
    114 
    115             // #7. 将转换后的缓冲复制到WriteFile的缓冲
    116             WriteProcessMemory(g_cpdi.hProcess, (LPVOID)dwAddrOfBuffer,
    117                 lpBuffer, dwNumOfBytesToWrite, NULL);
    118             //ctx.Rdx=
    119             // #8. 取消临时缓冲
    120             free(lpBuffer);
    121 
    122             // #9.将Thread Context的EIP更改为WriteFile()
    123             //   (现在已经过WriteFile() + 1)
    124     
    125             //BOOL WriteFile(
    126             //    HANDLE  hFile,//文件句柄  rcx
    127             //    LPCVOID lpBuffer,//数据缓存区指针 rdx 
    128             //    DWORD   nNumberOfBytesToWrite,//你要写的字节数 r8
    129             //    LPDWORD lpNumberOfBytesWritten,//用于保存实际写入字节数的存储区域的指针 r9
    130             //    LPOVERLAPPED lpOverlapped//OVERLAPPED结构体指针 rsp+0x20    [call 前rsp 0 8 10 18 20 28]
    131             //);
    132             /*ctx.Rdx += 1;
    133             ctx.R8 -= 1;*/
    134             ctx.Rip =(DWORD64)g_pfWriteFile;
    135             //ctx.Eip = (DWORD)g_pfWriteFile;
    136             SetThreadContext(g_cpdi.hThread, &ctx);
    137 
    138             // #10. Debuggee 运行被调试进程
    139             ContinueDebugEvent(pde->dwProcessId, pde->dwThreadId, DBG_CONTINUE);
    140             Sleep(0);
    141             printf("continue
    ");
    142             // #11. API Hook
    143             WriteProcessMemory(g_cpdi.hProcess, g_pfWriteFile,&g_chINT3, sizeof(BYTE), NULL);
    144 
    145             return TRUE;
    146         }
    147     }
    148 
    149     return FALSE;
    150 }
    151 
    152 void DebugLoop()
    153 {
    154     DEBUG_EVENT de;
    155     DWORD dwContinueStatus;
    156 
    157     // 从Debuggee等待event的到来。
    158     while (WaitForDebugEvent(&de, INFINITE))
    159     {
    160         dwContinueStatus = DBG_CONTINUE;
    161 
    162         // 创建Debuggee进程或attach事件
    163         if (CREATE_PROCESS_DEBUG_EVENT == de.dwDebugEventCode)
    164         {
    165             OnCreateProcessDebugEvent(&de);
    166             printf("finish creat debuggee
    ");
    167         }
    168         // 异常活动
    169         else if (EXCEPTION_DEBUG_EVENT == de.dwDebugEventCode)
    170         {
    171             if (OnExceptionDebugEvent(&de))
    172                 continue;
    173         }
    174         // Debuggee进程退出事件
    175         else if (EXIT_PROCESS_DEBUG_EVENT == de.dwDebugEventCode)
    176         {
    177             // debuggee结束-> debugger结束
    178             break;
    179         }
    180 
    181         // Debuggee的恢复执行。
    182         ContinueDebugEvent(de.dwProcessId, de.dwThreadId, dwContinueStatus);
    183     }
    184 }
    185 
    186 int main()
    187 {
    188     //system("tasklist");
    189     system("tasklist | findstr notepad");
    190     char pid[10];
    191     printf("输入要注入的进程pid:
    ");
    192     scanf_s("%s", pid, 10);
    193 
    194     DWORD dwPID;
    195     dwPID = atoi(pid);
    196     if (!DebugActiveProcess(dwPID))
    197     {
    198         printf("DebugActiveProcess(%d) failed!!!
    "
    199             "Error Code = %d
    ", dwPID, GetLastError());
    200         return 1;
    201     }
    202 
    203     // 调试器循环
    204     DebugLoop();
    205     system("pause");
    206     return 0;
    207     /*std::cout << "Hello World!
    "; */
    208 }
    209 
    210 // 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
    211 // 调试程序: F5 或调试 >“开始调试”菜单
    212 
    213 // 入门提示: 
    214 //   1. 使用解决方案资源管理器窗口添加/管理文件
    215 //   2. 使用团队资源管理器窗口连接到源代码管理
    216 //   3. 使用输出窗口查看生成输出和其他消息
    217 //   4. 使用错误列表窗口查看错误
    218 //   5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
    219 //   6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件

    vs2017 

  • 相关阅读:
    ubuntu 10.04 修改双系统默认启动项
    ubuntu 系统目录结构
    在ubuntu 下搭建 android开发环境
    android 开发包的离线安装方式
    wget 下载ftp整个目录
    Lambda复合条件以及获得EntityFramework 运行后生成的sql 命令
    解决jquery 的datepicker 的本地化以及Today问题
    ubuntu ssh 登录慢问题
    android监控上传小demo之第三步 相片的提交
    临时转mysql编码解决乱码问题
  • 原文地址:https://www.cnblogs.com/DirWang/p/11839060.html
Copyright © 2020-2023  润新知