设为首页 收藏本站
查看: 459|回复: 0

在Windows 2003中HOOK ZwCreateProcessEx

[复制链接]

尚未签到

发表于 2015-5-4 05:27:12 | 显示全部楼层 |阅读模式
作者:ZwelL

工作需要,想控制进程的创建,于是HOOK了ZwCreateProcess,后来发现xp和2003中创建进程的都用NtCreateProcessEx(参见[1])。
但是ZwCreateProcessEx未被ntoskrnl.exe导出,用softice的ntcall命令也没有看到,网上也没有找到相关代码。没办法,跟踪ntoskrnl!ZwCreateProcess
>u ntoskrnl!ZwCreateProcessEx

_ZwCreateProcess
0008:804e7ae2    bb32000000    mov eax, 00000032

但是ZwCreateProcessEx有9个参数,最后一个未知,4字节,猜成HANDLE型。
原型如下:
typedef NTSTATUS (*NTCREATEPROCESSEX)(
    OUT PHANDLE ProcessHandle,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
    IN HANDLE ParentProcess,
    IN BOOLEAN InheritObjectTable,
    IN HANDLE SectionHandle OPTIONAL,
    IN HANDLE DebugPort OPTIONAL,
    IN HANDLE ExceptionPort OPTIONAL,
    IN HANDLE Unknown );  
最终用硬编码HOOK 成功,代码如下:


#include "ntddk.h"
#include "stdarg.h"
#include "stdio.h"
#include "ntiologc.h"

#define DWORD unsigned long
#define WORD unsigned short
#define BOOL unsigned long

typedef struct ServiceDescriptorEntry {
    unsigned int *ServiceTableBase;
    unsigned int *ServiceCounterTableBase; //Used only in checked build
    unsigned int NumberOfServices;
    unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry, *PServiceDescriptorTableEntry;

extern PServiceDescriptorTableEntry KeServiceDescriptorTable;

typedef NTSTATUS (*NTCREATEPROCESSEX)(
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN HANDLE ParentProcess,
IN BOOLEAN InheritObjectTable,
IN HANDLE SectionHandle OPTIONAL,
IN HANDLE DebugPort OPTIONAL,
IN HANDLE ExceptionPort OPTIONAL,
IN HANDLE Unknown );

NTCREATEPROCESSEX    OldNtCreateProcessEx;

// Length of process name (rounded up to next DWORD)
#define PROCNAMELEN     20
// Maximum length of NT process name
#define NT_PROCNAMELEN  16
ULONG gProcessNameOffset;

void GetProcessNameOffset()
{
   
    PEPROCESS curproc;
    int i;
    curproc = PsGetCurrentProcess();
    for( i = 0; i < 3*PAGE_SIZE; i++ )
    {
        if( !strncmp( "System", (PCHAR) curproc + i, strlen("System") ))
        {
            gProcessNameOffset = i;
        }
    }
}

BOOL GetProcessName( PCHAR theName )
{
    PEPROCESS       curproc;
    char            *nameptr;
    ULONG           i;
    KIRQL           oldirql;

    if( gProcessNameOffset )
    {
        curproc = PsGetCurrentProcess();
        nameptr   = (PCHAR) curproc + gProcessNameOffset;
        strncpy( theName, nameptr, NT_PROCNAMELEN );
        theName[NT_PROCNAMELEN] = 0; /* NULL at end */
        return TRUE;
    }
    return FALSE;
}

NTSTATUS NewNtCreateProcessEx(
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN HANDLE ParentProcess,
IN BOOLEAN InheritObjectTable,
IN HANDLE SectionHandle OPTIONAL,
IN HANDLE DebugPort OPTIONAL,
IN HANDLE ExceptionPort OPTIONAL,
IN HANDLE Unknown OPTIONAL)
{
    CHAR aProcessName[PROCNAMELEN];
        
    GetProcessName( aProcessName );
    DbgPrint("rootkit: NewNtCreateProcessEx() from %s\n", aProcessName);
    //DbgPrint("ok");
    return OldNtCreateProcessEx(ProcessHandle,DesiredAccess,
            ObjectAttributes,ParentProcess,InheritObjectTable,SectionHandle,DebugPort,ExceptionPort,Unknown);
}

NTSTATUS
OnStubDispatch(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP           Irp
    )
{
    Irp->IoStatus.Status      = STATUS_SUCCESS;
    IoCompleteRequest (Irp,
                       IO_NO_INCREMENT
                       );
    return Irp->IoStatus.Status;
}

VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
{
    DbgPrint("ROOTKIT: OnUnload called\n");

    _asm
    {
        CLI                    //dissable interrupt
        MOV    EAX, CR0        //move CR0 register into EAX
        AND EAX, NOT 10000H //disable WP bit
        MOV    CR0, EAX        //write register back
    }

    (NTCREATEPROCESSEX)(*(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase + 0x32))=OldNtCreateProcessEx;

    _asm
    {
        MOV    EAX, CR0        //move CR0 register into EAX
        OR    EAX, 10000H        //enable WP bit     
        MOV    CR0, EAX        //write register back        
        STI                    //enable interrupt
    }
}

NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
{
    int i;

    DbgPrint("My Driver Loaded!");
    GetProcessNameOffset();

    // Register a dispatch function
    for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
    {
            theDriverObject->MajorFunction = OnStubDispatch;
    }

    theDriverObject->DriverUnload  = OnUnload;

    // save old system call locations
    //OldNtCreateProcessEx=(NTCREATEPROCESSEX)(SYSTEMSERVICE(0x32));
    OldNtCreateProcessEx=(NTCREATEPROCESSEX)(*(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase + 0x32));


    _asm
    {
        CLI                    //dissable interrupt
        MOV    EAX, CR0        //move CR0 register into EAX
        AND EAX, NOT 10000H //disable WP bit
        MOV    CR0, EAX        //write register back
    }

    (NTCREATEPROCESSEX)(*(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase + 0x32))=  NewNtCreateProcessEx;

    _asm
    {
        MOV    EAX, CR0        //move CR0 register into EAX
        OR    EAX, 10000H        //enable WP bit     
        MOV    CR0, EAX        //write register back        
        STI                    //enable interrupt
    }
                    
    return STATUS_SUCCESS;
}

这样很不爽,每次都要这样看索引号,问了SOBEIT,可以通过从NTDLL中这样获取服务索引号:
来自rookkit:

#include
#include

BOOL GetId( char *FuncName, ULONG *FunctionID )
{
    //get the function's address
    PBYTE Function = (PBYTE)GetProcAddress( GetModuleHandle( "ntdll.dll" ), FuncName );
    /*
    do some sanity checks,
    make sure this function
    has a corresponding kernel
    level function
    */

    *FunctionID = 0;

    //func not found...
    if ( Function == NULL )
    {
        return FALSE;
    }

    /*
    77F5B438   B8 00000000    MOV EAX, _FUNCTION_ID_
    77F5B43D   BA 0003FE7F    MOV EDX,7FFE0300
    77F5B442   FFD2           CALL EDX
    77F5B444   C2 1800        RETN XX
     */

    //mov eax
    if ( *Function != 0xB8 )
    {
        return FALSE;
    }
    /*
    since the address of
    the function which
    actually makes the call
    (SYSCALL) may change, we just
    check for mov edx
    */
    if ( *(Function + 5) != 0xBA )
    {
        return FALSE;
    }

    //call edx
    /*if ( *(PWORD)(Function + 10) != 0xD2FF )
    {
        return FALSE;
    }
    //retn
    if ( *(Function + 12) != 0xC2 )
    {
        return FALSE;
    }*/

    *FunctionID = *(PDWORD)(Function + 1);
    return TRUE;
}

int main(int argc, char* argv[])
{
    ULONG Id;
   
    printf( "function name: NtCreateProcessEx\n" );

    GetId( "NtCreateProcessEx", &Id );
    printf( "function id: %08X\n", Id );
    return 0;
}
///////////////////////////////////////////////////////////////////////

这样也不爽,要从用户态传到驱动层不方便,最后,用这个代码:

#include "ntddk.h"
#include "stdarg.h"
#include "stdio.h"
#include "ntiologc.h"
#include "ntimage.h"


#define DWORD unsigned long
#define WORD unsigned short
#define BOOL unsigned long
#define BYTE unsigned char

#define SEC_IMAGE    0x01000000

typedef struct _SECTION_IMAGE_INFORMATION {
PVOID EntryPoint;
ULONG StackZeroBits;
ULONG StackReserved;
ULONG StackCommit;
ULONG ImageSubsystem;
WORD SubsystemVersionLow;
WORD SubsystemVersionHigh;
ULONG Unknown1;
ULONG ImageCharacteristics;
ULONG ImageMachineType;
ULONG Unknown2[3];
} SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION;

DWORD GetDllFunctionAddress(char* lpFunctionName, PUNICODE_STRING pDllName)
{
    HANDLE hThread, hSection, hFile, hMod;
    SECTION_IMAGE_INFORMATION sii;
    IMAGE_DOS_HEADER* dosheader;
    IMAGE_OPTIONAL_HEADER* opthdr;
    IMAGE_EXPORT_DIRECTORY* pExportTable;
    DWORD* arrayOfFunctionAddresses;
    DWORD* arrayOfFunctionNames;
    WORD* arrayOfFunctionOrdinals;
    DWORD functionOrdinal;
    DWORD Base, x, functionAddress;
    char* functionName;
    STRING ntFunctionName, ntFunctionNameSearch;
    PVOID BaseAddress = NULL;
    SIZE_T size=0;

    OBJECT_ATTRIBUTES oa = {sizeof oa, 0, pDllName, OBJ_CASE_INSENSITIVE};

    IO_STATUS_BLOCK iosb;

    //_asm int 3;
    ZwOpenFile(&hFile, FILE_EXECUTE | SYNCHRONIZE, &oa, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);

    oa.ObjectName = 0;

    ZwCreateSection(&hSection, SECTION_ALL_ACCESS, &oa, 0,PAGE_EXECUTE, SEC_IMAGE, hFile);
   
    ZwMapViewOfSection(hSection, NtCurrentProcess(), &BaseAddress, 0, 1000, 0, &size, (SECTION_INHERIT)1, MEM_TOP_DOWN, PAGE_READWRITE);
   
    ZwClose(hFile);
   
    hMod = BaseAddress;
   
    dosheader = (IMAGE_DOS_HEADER *)hMod;
   
    opthdr =(IMAGE_OPTIONAL_HEADER *) ((BYTE*)hMod+dosheader->e_lfanew+24);

    pExportTable =(IMAGE_EXPORT_DIRECTORY*)((BYTE*) hMod + opthdr->DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT]. VirtualAddress);

    // now we can get the exported functions, but note we convert from RVA to address
    arrayOfFunctionAddresses = (DWORD*)( (BYTE*)hMod + pExportTable->AddressOfFunctions);

    arrayOfFunctionNames = (DWORD*)( (BYTE*)hMod + pExportTable->AddressOfNames);

    arrayOfFunctionOrdinals = (WORD*)( (BYTE*)hMod + pExportTable->AddressOfNameOrdinals);

    Base = pExportTable->Base;

    RtlInitString(&ntFunctionNameSearch, lpFunctionName);

    for(x = 0; x < pExportTable->NumberOfFunctions; x++)
    {
        functionName = (char*)( (BYTE*)hMod + arrayOfFunctionNames[x]);

        RtlInitString(&ntFunctionName, functionName);

        functionOrdinal = arrayOfFunctionOrdinals[x] + Base - 1; // always need to add base, -1 as array counts from 0
        // this is the funny bit.  you would expect the function pointer to simply be arrayOfFunctionAddresses[x]...
        // oh no... thats too simple.  it is actually arrayOfFunctionAddresses[functionOrdinal]!!
        functionAddress = (DWORD)( (BYTE*)hMod + arrayOfFunctionAddresses[functionOrdinal]);
        if (RtlCompareString(&ntFunctionName, &ntFunctionNameSearch, TRUE) == 0)
        {
            ZwClose(hSection);
            return functionAddress;
        }
    }

    ZwClose(hSection);
    return 0;
}

NTSTATUS
OnStubDispatch(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP           Irp
    )
{
    Irp->IoStatus.Status      = STATUS_SUCCESS;
    IoCompleteRequest (Irp,
                       IO_NO_INCREMENT
                       );
    return Irp->IoStatus.Status;
}

VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
{
    DbgPrint("ROOTKIT: OnUnload called\n");
}

NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
{
    int i;
    UNICODE_STRING dllName;
    DWORD functionAddress;
    int    position;
    DbgPrint("My Driver Loaded!");
    theDriverObject->DriverUnload  = OnUnload;
    RtlInitUnicodeString(&dllName, L"\\Device\\HarddiskVolume1\\Windows\\System32\\ntdll.dll");
    functionAddress = GetDllFunctionAddress("ZwCreateProcessEx", &dllName);
    position = *((WORD*)(functionAddress+1));

    DbgPrint("Id:%d\n", position);
                    
    return STATUS_SUCCESS;
}

上面的代码从驱动层加载NTDLL,再从输出表中找出函数地址,mov eax,[ID]对应的b8后面的字就是索引号,其实跟前一个代码作用是相似的,
只是驱动层没有LoadLibrary,只能这样解决了。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-63237-1-1.html 上篇帖子: Windows 2003中IIS 6.0应用程序池回收和工作进程 下篇帖子: 配置更安全的服务器Windows 2003 Server
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表