WINAPI里的CreateThread函数
传给CreateThread的函数,必须是全局函数或静态函数,不能使用类的普通函数即,你可以使用如下函数声明:static DWORD WINAPI Run(LPVOID LpParameter);因为类的普通函数会传递类对象指针作为隐含参数,所以与CreateThread所要求的函数类型不匹配
驱动下怎么调用ZwReadVirtualMemory函数
/************************************************************************ 获取DLL中的函数地址 lpFunctionName 函数名称 pDllName DLL文件名称************************************************************************//***************************************************************************************** 原理: R0下没有LoadLibrary函数* 利用ZwCreateFile打开文件* 利用ZwCreateSection创建区段* 利用ZwMapViewOfSection映射区段到当前进程的虚拟内存* 定位PE Header地址* 定位第一个数据目录* 到EAT导出表* 搜索函数名,定位函数地址****************************************************************************************/ DWORD GetDllFunctionId(char* lpFunctionName, PUNICODE_STRING pDllName) { HANDLE 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; NTSTATUS status = STATUS_UNSUCCESSFUL; ZwOpenFile(&hFile, FILE_EXECUTE | SYNCHRONIZE, &oa, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT); oa.ObjectName = 0; //小红伞杀ZwCreateSection +ZwMapViewOfSection 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); 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 NumberOfFunctions; x++) { functionName = (char*)( (BYTE*)hMod + arrayOfFunctionNames[x]); RtlInitString(&ntFunctionName, functionName); functionOrdinal = arrayOfFunctionOrdinals[x] + Base - 1; functionAddress = (DWORD)( (BYTE*)hMod + arrayOfFunctionAddresses[functionOrdinal]); if (RtlCompareString(&ntFunctionName, &ntFunctionNameSearch, TRUE) == 0) { ZwClose(hSection); return functionAddress; } } ZwClose(hSection); return 0; } /************************************************************************ 根据DLL中函数的地址 找到在SSDT中索引号 lpFunctionName 函数名称************************************************************************/ PVOID* GetSSDTFunctionAddress(char* lpFunctionName){ DWORD FunctionId = 0; ULONG Pread = 0; UNICODE_STRING DllName; RtlInitUnicodeString(&DllName,L"\\Device\\HarddiskVolume1\\Windows\\System32\\ntdll.dll"); FunctionId=GetDllFunctionId(lpFunctionName,&DllName); Pread=*((WORD *)(FunctionId+1)); return (KeServiceDescriptorTable->ServiceTable[Pread]); }
typedef DWORD (CALLBACK* LPREGISTERSERVICEPROCESS)(...
定义了一个函数指针类型为 LPREGISTERSERVICEPROCESS,函数返回值为 DWORD,参数为两个 DWORD 类型。
函数指针说起来比较麻烦,以带两个 int 参数的函数指针为例,一看就明白:#include typedef int (*PFNTEST)(int, int);int test1(int a, int b){return (a+b);}int test2(int a, int b){return (a-b);}int call(int i, PFNTEST pfn){return (*pfn)(i*i, i);}int main(){int m, n, p, q;PFNTEST pfnTest;pfnTest = &test1;m = (*pfnTest)(3, 5);pfnTest = &test2;n = (*pfnTest)(6, 2);p = call(4, test1);q = call(7, test2);printf("%d, %d, %d, %d.", m, n, p, q);return 0;}输出结果:8, 4, 20, 42.Windows SDK 定义:#define CALLBACK __stdcall其中采用 __stdcall 调用约定,可能是微软在 dll 内部对该函数指针也指明了这种调用约定,所以你声明的时候也需要指定,才能正确调用。
GetTickCount和timeGetTime两个函数的区别
在精度要求较高的情况下,VC中可以利用GetTickCount()函数,该函数的返回值是 DWORD型,表示以ms为单位的计算机启动后经历的时间间隔。
精度比WM_TIMER消息映射高,在较 短的定时中其计时误差为15ms,在较长的定时中其计时误差较低,如果定时时间太长,就好象死机一样,CPU占用率非常高,只能用于要求不高的延时程序中。
与GetTickCount()函数类似的多媒体定时器函数DWORD timeGetTime(void),该函数定时精 度为ms级,返回从Windows启动开始经过的毫秒数。
微软公司在其多媒体Windows中提供了精确定时器的底 层API持,利用多媒体定时器可以很精确地读出系统的当前时间,并且能在非常精确的时间间隔内完成一 个事件、函数或过程的调用。
不同之处在于调用DWORD timeGetTime(void) 函数之前必须将 Winmm.lib 和 Mmsystem.h 添加到工程中,否则在编译时提示DWORD timeGetTime(void)函数未定义。
由于使用该 函数是通过查询的方式进行定时控制的,所以,应该建立定时循环来进行定时事件的控制。
c++ windows.h中有什么函数?
windows.h下几个函数的使用 有关进程系统权限类1:函数OpenProcessToken( HANDLE ProcessHandle,//进程的句柄 DWORD DesiredAccess,//对进程的访问描述 PHANDLE TokenHandle//打开进程令牌的句柄指针); 这个函数的作用是打开进程令牌2: 函数LookupPrivilegeValue( LPCTSTR lpSytemName,//系统名称 LPCTSTR lpName,//特权名称 PLUID lpluid//本地系统唯一的ID号) 这个函数将返回一个本地系统内独一无二的ID,来用于系统权限的更改,它的第一个参数是系统名,nil表示本系统。
第2个参数是特权的名字。
第3个参数用来接收函数返回的ID。
3.函数AdjustTokenPrivileges( HANDLE TokenHandle, //更改权限的令牌环句柄 BOOL DisableAllPrivileges, //是否修改所有权限的标志位 PTOKEN_PRIVILEGES NewState, //新的系统权限信息 DWORD BufferLength, //上一个参数的长度 PTOKEN_PRIVILEGES PreviousState, // 返回更改系统特权以前的权限 PDWORD ReturnLength //上一个参数的长度); 这个函数用于更改进程的系统权限 ,第1个参数是要更改权限的令牌环句柄。
第2个参数如果为true表示更改所有的系统权限 ,false表示更改部分。
第3个参数是要更改的系统特权的值。
第4个参数是第3个参数的大小。
第5个参数返回更改系统特权以前的权限,我们不需要就设为nil。
第6个参数是第5个参数的大小。
OpenProcess( DWORD dwDesiredAccess,//访问标志 BOOL bInheritHandle,//继承句柄标志 DWORD dwProcessId //进程Id) 这个函数用于修改我们宿主进程的一些属性,这些属性放在第一个参数里面比如说PROCESS_VM_OPEARTION就是允许远程VM操作,即允许VirtualProtectEx和WriteProcessMemory函数操作本进程内存空间。
PROCESS_VM_WRITE就是允许远程VM写,即允许WriteProcessMemory函数访问本进程的内存空间。
第二个参数是一个标志参数,用来确定返回的句柄是否可以被新的进程继承。
我们的程序中设为False。
第三个参数需要操作的进程Id,也就是我们的宿主进程的ID。
2:函数VirtualAllocEx( HANDLE hProcess,//要进行操作的进程句柄,当然是我们的宿主了 LPVOID lpAddress,//分配空间的开始地址 DWORD dwSize,//分配空间的大小 DWORD flAllocationType,//分配空间的类型 DWOrd flProtect//访问保护类型 ) 我们使用VirtualAllocEx函数在宿主进程中开辟一块内存空间,用于存放dll的文件名,VirtualAllocEx的第一参数是要操作的进程,第二个是开始地址,第三个是长度,第4,5个是操作参数。
其中MEM_COMMIT表示本函数分配的物理内存或者是内存的页面文件,PAGE_READWRITE表示分配的区域内允许读写 函数WriteProcessMemory( HANDLE hProcess,//所要操作的线程的句柄 LPVOID lpBaseAddress,//开始进行操作的起始地址 LPVOID lpBuffer,//所要写入的Bytes数 LPDWORD lpNuberofBytersWriteen//世纪写入的Bytes数 ) 前面的函数在宿主内存中创建号空间后,现在往里面写入dll的名称,而我们的WriteProcessMemory函数就可以胜任这一项工作,WriteProcessMemory函数的第一个参数是需要往内存里面写入dd的进程句柄,第二个参数是 “要进行写操作”的目标内存起始地址,第三个参数是 “需要被写入的数据”的地址,第四个参数是准备要写入的长度,第五个参数是实际操作中写的长度,这个参数是被函数输出的。
到这里我们就已经能成功把dll的路径名称写进了宿主的内存空间。
GetProcAddress( HMODULE hModule, //dll模块的句柄 LPCSTR lpProcName // 函数名称 ); 我们用这个函数主要想得到kernel32.dll中的函数LoadLibraryW的入口地址,所以 GetProcAddress(GetModuleHandle('Kernel32'), 'LoadLibraryW')就可以了,当然有些细节得符合程序编译器的要求,VC下使用就要改成 GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW")的形式。
CreateRemoteThread ( HANDLE hProcess, //要进行操作的进程句柄,也就是我们的宿主句柄 LPSECURITY_ATTRIBUTES lpThreadAttributes, //线程安全属性的指针 DWORD dwStackSize, //初始化堆(stack)的大小 LPTHREAD_START_ROUTINE lpStartAddress,//新建线程函数的指针,或叫做地址 LPVOID lpParameter, //新建线程函数的参数 DWORD dwCreationFlags, //标志位 LPDWORD lpThreadId //线程返回值); 这个函数就是本文的点睛之笔了,我们之前所做所有的一切,都是在为它做准备工作,它的功能就是在其他任何进程中创建新的线程,让其他的程序或进程附加执行我们的代码。
CreateRemoteThread函数的第一个参数是要操作的宿主进程句柄;第二个参数为线程安全参数的指针,这里设为nil;第三个参数为初始化堆(stack)的大小,这里设0;第四个参数为新建线程函数的指针或叫做地址或叫入口;第五个参数为新建线程函数的参数,这里就是我们的dll路径名称;第六个参数是标志位,这里设0;第七个参数是线程返回值。
RegEnumValue函数读取注册表中的REG
在精度要求较高的情况下,VC中可以利用GetTickCount()函数,该函数的返回值是 DWORD型,表示以ms为单位的计算机启动后经历的时间间隔。
精度比WM_TIMER消息映射高,在较 短的定时中其计时误差为15ms,在较长的定时中其计时误差较低,如果定时时间太长,就好象死机一样,CPU占用率非常高,只能用于要求不高的延时程序中。
与GetTickCount()函数类似的多媒体定时器函数DWORD timeGetTime(void),该函数定时精 度为ms级,返回从Windows启动开始经过的毫秒数。
微软公司在其多媒体Windows中提供了精确定时器的底 层API持,利用多媒体定时器可以很精确地读出系统的当前时间,并且能在非常精确的时间间隔内完成一 个事件、函数或过程的调用。
不同之处在于调用DWORD timeGetTime(void) 函数之前必须将 Winmm.lib 和 Mmsystem.h 添加到工程中,否则在编译时提示DWORD timeGetTime(void)函数未定义。
由于使用该 函数是通过查询的方式进行定时控制的,所以,应该建立定时循环来进行定时事件的控制。
...
c++ windows.h中有什么函数?
windows.h下几个函数的使用有关进程系统权限类1:函数OpenProcessToken( HANDLE ProcessHandle,//进程的句柄 DWORD DesiredAccess,//对进程的访问描述 PHANDLE TokenHandle//打开进程令牌的句柄指针); 这个函数的作用是打开进程令牌2: 函数LookupPrivilegeValue( LPCTSTR lpSytemName,//系统名称 LPCTSTR lpName,//特权名称 PLUID lpluid//本地系统唯一的ID号)这个函数将返回一个本地系统内独一无二的ID,来用于系统权限的更改,它的第一个参数是系统名,nil表示本系统。
第2个参数是特权的名字。
第3个参数用来接收函数返回的ID。
3.函数AdjustTokenPrivileges(HANDLE TokenHandle, //更改权限的令牌环句柄BOOL DisableAllPrivileges, //是否修改所有权限的标志位PTOKEN_PRIVILEGES NewState, //新的系统权限信息DWORD BufferLength, //上一个参数的长度PTOKEN_PRIVILEGES PreviousState, // 返回更改系统特权以前的权限PDWORD ReturnLength //上一个参数的长度);这个函数用于更改进程的系统权限 ,第1个参数是要更改权限的令牌环句柄。
第2个参数如果为true表示更改所有的系统权限 ,false表示更改部分。
第3个参数是要更改的系统特权的值。
第4个参数是第3个参数的大小。
第5个参数返回更改系统特权以前的权限,我们不需要就设为nil。
第6个参数是第5个参数的大小。
OpenProcess( DWORD dwDesiredAccess,//访问标志 BOOL bInheritHandle,//继承句柄标志 DWORD dwProcessId //进程Id) 这个函数用于修改我们宿主进程的一些属性,这些属性放在第一个参数里面比如说PROCESS_VM_OPEARTION就是允许远程VM操作,即允许VirtualProtectEx和WriteProcessMemory函数操作本进程内存空间。
PROCESS_VM_WRITE就是允许远程VM写,即允许WriteProcessMemory函数访问本进程的内存空间。
第二个参数是一个标志参数,用来确定返回的句柄是否可以被新的进程继承。
我们的程序中设为False。
第三个参数需要操作的进程Id,也就是我们的宿主进程的ID。
2:函数VirtualAllocEx( HANDLE hProcess,//要进行操作的进程句柄,当然是我们的宿主了 LPVOID lpAddress,//分配空间的开始地址 DWORD dwSize,//分配空间的大小 DWORD flAllocationType,//分配空间的类型 DWOrd flProtect//访问保护类型) 我们使用VirtualAllocEx函数在宿主进程中开辟一块内存空间,用于存放dll的文件名,VirtualAllocEx的第一参数是要操作的进程,第二个是开始地址,第三个是长度,第4,5个是操作参数。
其中MEM_COMMIT表示本函数分配的物理内存或者是内存的页面文件,PAGE_READWRITE表示分配的区域内允许读写 函数WriteProcessMemory( HANDLE hProcess,//所要操作的线程的句柄 LPVOID lpBaseAddress,//开始进行操作的起始地址 LPVOID lpBuffer,//所要写入的Bytes数 LPDWORD lpNuberofBytersWriteen//世纪写入的Bytes数) 前面的函数在宿主内存中创建号空间后,现在往里面写入dll的名称,而我们的WriteProcessMemory函数就可以胜任这一项工作,WriteProcessMemory函数的第一个参数是需要往内存里面写入dd的进程句柄,第二个参数是 “要进行写操作”的目标内存起始地址,第三个参数是 “需要被写入的数据”的地址,第四个参数是准备要写入的长度,第五个参数是实际操作中写的长度,这个参数是被函数输出的。
到这里我们就已经能成功把dll的路径名称写进了宿主的内存空间。
GetProcAddress(HMODULE hModule, //dll模块的句柄LPCSTR lpProcName // 函数名称 );我们用这个函数主要想得到kernel32.dll中的函数LoadLibraryW的入口地址,所以GetProcAddress(GetModuleHandle('Kernel32'), 'LoadLibraryW')就可以了,当然有些细节得符合程序编译器的要求,VC下使用就要改成GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW")的形式。
CreateRemoteThread (HANDLE hProcess, //要进行操作的进程句柄,也就是我们的宿主句柄 LPSECURITY_ATTRIBUTES lpThreadAttributes, //线程安全属性的指针 DWORD dwStackSize, //初始化堆(stack)的大小LPTHREAD_START_ROUTINE lpStartAddress,//新建线程函数的指针,或叫做地址LPVOID lpParameter, //新建线程函数的参数 DWORD dwCreationFlags, //标志位LPDWORD lpThreadId //线程返回值);这个函数就是本文的点睛之笔了,我们之前所做所有的一切,都是在为它做准备工作,它的功能就是在其他任何进程中创建新的线程,让其他的程序或进程附加执行我们的代码。
CreateRemoteThread函数的第一个参数是要操作的宿主进程句柄;第二个参数为线程安全参数的指针,这里设为nil;第三个参数为初始化堆(stack)的大小,这里设0;第四个参数为新建线程函数的指针或叫做地址或叫入口;第五个参数为新建线程函数的参数,这里就是我们的dll路径名称;第六个参数是标志位,这里设0;第七个参数是线程返回值。
1、_stdcall是Pascal方式清理 C方式压栈,通常用于Win32 Api中,函数采用从右到左的压栈方式,自己在退出时清空堆栈。
VC将函数编译后会在函数名前面加上下划线前缀,在函数名后加上"@"和参数的字节数。
int f(void *p) -->> _f@4(在外部汇编语言里可以用这个名字引用这个函数)2、C调用约定(即用__cdecl关键字说明)(The C default calling convention)按从右至左的顺序压参数入栈,由调用者把参数弹出栈。
对于传送参数的内存栈是由调用者来维护的(正因为如此,实现可变参数vararg的函数(如printf)只能使用该调用约定)。
另外,在函数名修饰约定方面也有所不同。
_cdecl是C和C++程序的缺省调用方式。
每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。
函数采用从右到左的压栈方式。
VC将函数编译后会在函数名前面加上下划线前缀。
3、__fastcall调用的主要特点就是快,因为它是通过寄存器来传送参数的(实际上,它用ECX和EDX传送前两个双字(DWORD)或更小的参数,剩下的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的内存栈),在函数名修饰约定方面,它和前两者均不同。
__fastcall方式的函数采用寄存器传递参数,VC将函数编译后会在函数名前面加上"@"前缀,在函数名后加上"@"和参数的字节数。
4、thiscall仅仅应用于“C++”成员函数。
this指针存放于CX/ECX寄存器中,参数从右到左压。
thiscall不是关键词,因此不能被程序员指定。
5、naked call。
当采用1-4的调用约定时,如果必要的话,进入函数时编译器会产生代码来保存ESI,EDI,EBX,EBP寄存器,退出函数时则产生代码恢复这些寄存器的内容。
(这些代码称作 prolog and epilog code,一般,ebp,esp的保存是必须的).但是naked call不产生这样的代码。
naked call不是类型修饰符,故必须和_declspec共同使用。
关键字 __stdcall、__cdecl和__fastcall可以直接加在要输出的函数前。
它们对应的命令行参数分别为/Gz、/Gd和/Gr。
缺省状态为/Gd,即__cdecl。
要完全模仿PASCAL调用约定首先必须使用__stdcall调用约定,至于函数名修饰约定,可以通过其它方法模仿。
还有一个值得一提的是WINAPI宏,Windows.h支持该宏,它可以将出函数翻译成适当的调用约定,在WIN32中,它被定义为__stdcall。
使用WINAPI宏可以创建自己的APIs。
vc中的CopyFileEx函数
// 推动进度条的回调函数DWORD CALLBACK CopyProgressRoutine( LARGE_INTEGER TotalFileSize, // 文件总字节数 LARGE_INTEGER TotalBytesTransferred, // 已复制的字节数 LARGE_INTEGER StreamSize, // 当前流的字节数 LARGE_INTEGER StreamBytesTransferred, // 当前流已拷贝的字节数 DWORD dwStreamNumber, // 当前流序号 DWORD dwCallbackReason, // 回调函数的状态; 下面有补充... HANDLE hSourceFile, // 源文件句柄 HANDLE hDestinationFile, // 目标文件句柄 LPVOID lpData // CopyFileEx 传递的参数指针 /* dwCallbackReason(回调函数的状态): CALLBACK_CHUNK_FINISHED = $00000000; { 复制进行中 } CALLBACK_STREAM_SWITCH = $00000001; { 准备开始} //回调函数可以使用的返回值: PROGRESS_CONTINUE = 0; { 继续 } PROGRESS_CANCEL = 1; { 取消 } PROGRESS_STOP = 2; { 暂停 } PROGRESS_QUIET = 3; { 终止回调, 但不停止复制 } */)...