搜索WinExec地址参考

内核API定位与Windows版本检测
本文介绍了一种在Windows内核模式下通过搜索kern32.dll来定位特定API地址的方法,并提供了一个用于检测不同Windows版本的实用函数。
by
boywhp
/*
*    在kern32.dll中搜索指定API地址
*    Hash(WinExec) = 0x72dc Hash(LoadLibraryA) = 0xae14
*/
ULONG
SearchApi(WORD api_hash)

{
    //搜索k32dll的API地址
    PEPROCESS pSystemProcess = PsGetCurrentProcess(); //make sure you are running at IRQL PASSIVE_LEVEL
    PLIST_ENTRY pCurrentList = (PLIST_ENTRY)((PUCHAR)pSystemProcess + 0xA0);
    PLIST_ENTRY pTempList = pCurrentList;
    PEPROCESS pEProcess = NULL;
   
    do {
        PPEB peb = NULL;
        PUCHAR lpname = NULL;

        pEProcess = (PEPROCESS)((PUCHAR)pTempList - 0xA0);
        peb = (PPEB)(*(PULONG)((PUCHAR)pEProcess + 0x1b0));
        lpname = (PUCHAR)pEProcess + 0x1fc;

        KdPrint(("%s/n", lpname));

        if ((peb != NULL)
            && (strncmp(lpname, "winlogon", 8) == 0))
        {
            ULONG api_addr = 0;
            KeAttachProcess((PKPROCESS)pEProcess);
            KdPrint(("ImageBaseAddress:%08x/n", peb->ImageBaseAddress));
   
            _asm
            {
                mov eax, peb;
                mov eax, [eax+0x0c];//ldr
                mov esi, [eax+0x1c];//esi->ldr.InInitializationOrderMoudleList _LIST_ENTRY struct
                lodsd;                //eax = [esi];
                mov ebx, [eax+0x08];//k32dll is the first! and baseaddress is follow _LIST_ENTRY
               
                //now get pe image infos to find LoadLibrary and GetProcAddress API
                //assert ebx is the pe image base!!!
               
                mov ax, api_hash;        //Hash(LoadLibraryA) = 0xae14
                //Hash(WinExec) = 0x72dc
                //call search_api;
                //mov [ebp-4], eax;    //this is LoadLibraryA API
               
                //------------------------------------------------------------------------------
                //ebx-PE Image Base,eax-hash of api name, return eax!!!
                //------------------------------------------------------------------------------
                //search_api:
                mov edx, eax;
                mov eax, [ebx+0x3c];        //File address of the new exe header
                mov eax, [eax+ebx+0x78];    //pe base ->data directory[16]
                add eax, ebx;                //get directory[0] Address ->export table ->eax
                mov esi, [eax+0x20];        //get export funs names rva
                add esi, ebx;                //esi->export names table address
                //mov ecx, [eax+0x18];        //get export funs numbers
               
                xor ecx, ecx;
                //search funs name tables
next_api:
               
                mov edi, [esi+ecx*4];        //
                add edi, ebx;
               
                //-----------------------------------
                //计算[edi]字符串的hash值
                //-----------------------------------
                pushad;
                xor eax, eax;
cacul_next:
                shl eax, 2;
                movzx ecx, byte ptr[edi];
                add ax, cx;
                inc edi;
                inc ecx;
                loop cacul_next;
                //test edx!!!
                cmp ax, dx;
                jz search_end;
               
                popad;
                inc ecx;
                jmp next_api;
               
search_end:
                popad;
                //ecx is the GetProcAdress index
                mov eax, [eax+0x1c];
                add eax, ebx;
                mov eax, [eax+4*ecx];
                add eax, ebx;
                mov api_addr, eax;
                //ret;
            }
            KdPrint(("%08x/n", api_addr));
           
            KeDetachProcess();
            return api_addr;
        }
        pTempList = pTempList->Flink;
    } while(pCurrentList != pTempList);
    return 0;
}
注意!仍然存在硬编码(主要是操作系统的EProcess数据结构各操作系统有变化)


 

测试操作的代码,该办法比PsGetVersion管用:-)PsGetVersion居然无法确定Windows2003 5.2.3790.0 和Windows2003 SP1 5.2.3790.1830

基于我假定EPROCESS数据结构变化,则EPROCESS中的镜像文件偏移必然变化的前提!!!希望大家帮我完善下

#define BASE_PROCESS_NAME_OFFSET_2K                0x01FC//NT5.0.2195.7133
#define BASE_PROCESS_NAME_OFFSET_XP                0x0174//NT5.1.2600.3093
#define BASE_PROCESS_NAME_OFFSET_2K3            0x0154//nt5.2.3790.0
#define BASE_PROCESS_NAME_OFFSET_2K3_SP1        0x0164//nt5.2.3790.1830
#define BASE_PROCESS_NAME_OFFSET_VISTA            0x014c

WORD GetWindowsVersion()
{
    PEPROCESS pSystemProcess = PsGetCurrentProcess();
    WORD offset;
    for (offset=0; offset < PAGE_SIZE; offset++)
    {
        if(strncmp("System", (PCHAR)pSystemProcess + offset, 6) == 0)
        {
            g_EProcessOffset.wOffsetName = offset;
            KdPrint(("%08x", offset));
            switch (offset)
            {
            case BASE_PROCESS_NAME_OFFSET_2K:
                KdPrint(("WINDOWS_VERSION_2K/n"));
                return WINDOWS_VERSION_2K;
                break;
            case BASE_PROCESS_NAME_OFFSET_XP:
                KdPrint(("WINDOWS_VERSION_XP/n"));
                return WINDOWS_VERSION_XP;
                break;
            case BASE_PROCESS_NAME_OFFSET_2K3:
                KdPrint(("WINDOWS_VERSION_2K3/n"));
                return WINDOWS_VERSION_2K3;
                break;
            case BASE_PROCESS_NAME_OFFSET_2K3_SP1:
                KdPrint(("WINDOWS_VERSION_2K3_SP1/n"));
                return WINDOWS_VERSION_2K3_SP1;
                break;
            case BASE_PROCESS_NAME_OFFSET_VISTA:
                KdPrint(("WINDOWS_VERSION_VISTA/n"));
                return WINDOWS_VERSION_VISTA;
                break;
            default:
                return WINDOWS_VERSION_NONE;
            }
        }
    }
    return WINDOWS_VERSION_NONE;
}

<think>嗯,用户想知道WinExec函数在Windows API中的用法。首先,我需要回忆一下WinExec的基本信息。WinExecWindows早期版本中用来执行应用程序的函数,但现在可能已经被更安全的函数取代了,比如CreateProcess。不过,用户可能还在维护旧代码,所以了解WinExec还是有必要的。 首先,我应该介绍函数的原型,包括参数和返回值。参数有两个,一个是命令行字符串,另一个是显示方式。比如,SW_SHOW和SW_HIDE这些常量,需要解释它们的用途。然后,返回值是UINT,但实际是错误码,需要说明成功和失败的情况。 接下来,要提供一个简单的代码示例。用户可能想看到如何实际调用这个函数,比如用C++写一个调用WinExec运行记事本的例子。需要注意的是,现在推荐使用CreateProcess,所以应该提醒用户这一点,并解释为什么,比如安全性更高,控制更细致。 然后,生成相关问题。用户可能想了解WinExec的替代方法,参数的具体含义,返回值处理,安全风险,与ShellExecute的区别,以及错误处理。这些问题应该覆盖常见的使用场景和潜在的问题。 同时,用户提供的引用中有关于内存锁定的函数,比如mlock,但这些可能与WinExec无关,所以不需要在回答中涉及。但需要确保引用正确,如果有相关的信息可以链接,但这里可能没有直接关联,所以可能不需要添加引用标识,除非有相关内容。 需要检查LaTeX格式是否符合要求,比如行内公式用$...$,独立公式用$$...$$。但在这个问题中,可能用不到数学公式,所以可以忽略这部分。但如果有代码块,需要用反引号包裹,并指定语言,比如C++。 最后,确保回答结构清晰,分点说明,帮助用户逐步了解WinExec的用法,注意事项,并提供相关问题引导进一步学习。同时要使用中文,保持自然的口语化,避免使用Markdown格式。</think>### WinExec函数用法说明 WinExecWindows API中用于运行可执行文件的函数,其原型为: $$UINT WinExec(LPCSTR lpCmdLine, UINT uCmdShow);$$ #### 参数说明: 1. `lpCmdLine`:包含执行命令的字符串,格式为`"程序路径 [参数]"`,路径包含空格时必须加引号 2. `uCmdShow`:窗口显示方式,常用值包括: - $SW_HIDE$ (隐藏窗口) - $SW_SHOWNORMAL$ (正常显示) - $SW_MAXIMIZE$ (最大化) #### 返回值: - 大于31表示成功 - 小于等于31为错误码,如: - $0$: 系统内存不足 - $ERROR_FILE_NOT_FOUND$ (值2): 文件未找到 #### 示例代码: ```cpp #include <windows.h> int main() { // 运行记事本并最大化窗口 WinExec("notepad.exe C:\\test.txt", SW_MAXIMIZE); return 0; } ``` #### 注意事项: 1. 该函数是16位Windows的遗留接口,推荐使用更安全的`CreateProcess`函数[^2] 2. 路径中的空格必须用双引号包裹,例如:`"C:\\Program Files\\app.exe"` 3. 无法获取进程退出码,需要进程控制时应使用`CreateProcess`
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值