参数表
参数 类型及说明
lpStartupInfo STARTUPINFO,指定一个STARTUPINFO结构,用于最终载入进程的启动信息
LoadLibraryA
获取一个进程的启动信息 参数表 参数 类型及说明 lpStartupInfo STARTUPINFO,指定一个STARTUPINFO结构,用于最终载入进程的启动信
lstrcmpiA
FreeLibrary
释放指定的动态链接库,它们早先是用LoadLibrary API函数装载...对LoadLibrary的每一次调用都应该有一个对应
VirtualAllocEx
VirtualAllocEx 函数的作用是在指定进程的虚拟空间保留或提交内存区域,除非指定MEM_RESET参数,否则将该内存区域置0。
LPVOID VirtualAllocEx(
HANDLE hProcess, // 申请内存所在的进程句柄
LPVOID lpAddress, // 保留页面的内存地址;一般用NULL自动分配
SIZE_T dwSize, // 欲分配的内存大小,字节单位;注意实际分 配的内存大小是页内存大小的整数倍
DWORD flAllocationType,
DWORD flProtect
);
WriteProcessMemory
WriteProcessMemory
VB函数原型:
Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, ByVal lpBaseAddress As Any, ByVal lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
作用:写内存
说明:
hProcess , 进程的句柄
lpBaseAddress, 进程地址
lpBuffer, 数据存放地址
nSize, 数据的长度
lpNumberOfBytesWritten,实际数据的长度
GetModuleHandleA
CreateRemoteThread和WriteProcessMemory技术
示例程序:WinSpy
另一种注入代码到其他进程地址空间的方法是使用WriteProcessMemory API。这次你不用编写一个独立的DLL而是直接复制你的代码到远程进程(WriteProcessMemory)并用CreateRemoteThread执行之。
让我们看一下CreateRemoteThread的声明:
HANDLE CreateRemoteThread(
HANDLE hProcess, // handle to process to create thread in
LPSECURITY_ATTRIBUTES lpThreadAttributes, // pointer to security
// attributes
DWORD dwStackSize, // initial thread stack size, in bytes
LPTHREAD_START_ROUTINE lpStartAddress, // pointer to thread
// function
LPVOID lpParameter, // argument for new thread
DWORD dwCreationFlags, // creation flags
LPDWORD lpThreadId // pointer to returned thread identifier
);
和CreateThread相比,有一下不同:
●增加了hProcess参数。这是要在其中创建线程的进程的句柄。
●CreateRemoteThread的lpStartAddress参数必须指向远程进程的地址空间中的函数。这个函数必须存在于远程进程中,所以我们不能简单地传递一个本地ThreadFucn的地址,我们必须把代码复制到远程进程。
●同样,lpParameter参数指向的数据也必须存在于远程进程中,我们也必须复制它。
现在,我们总结一下使用该技术的步骤:
1. 得到远程进程的HANDLE(OpenProcess)。
2. 在远程进程中为要注入的数据分配内存(VirtualAllocEx)、
3. 把初始化后的INJDATA结构复制到分配的内存中(WriteProcessMemory)。
4. 在远程进程中为要注入的数据分配内存(VirtualAllocEx)。
5. 把ThreadFunc复制到分配的内存中(WriteProcessMemory)。
6. 用CreateRemoteThread启动远程的ThreadFunc。
7. 等待远程线程的结束(WaitForSingleObject)。
8. 从远程进程取回指执行结果(ReadProcessMemory 或 GetExitCodeThread)。
9. 释放第2、4步分配的内存(VirtualFreeEx)。
10. 关闭第6、1步打开打开的句柄。
另外,编写ThreadFunc时必须遵守以下规则:
1. ThreadFunc不能调用除kernel32.dll和user32.dll之外动态库中的API函数。只有kernel32.dll和 user32.dll(如果被加载)可以保证在本地和目的进程中的加载地址是一样的。(注意:user32并不一定被所有的Win32进程加载!)参考附 录A。如果你需要调用其他库中的函数,在注入的代码中使用LoadLibrary和GetProcessAddress强制加载。如果由于某种原因,你需 要的动态库已经被映射进了目的进程,你也可以使用GetMoudleHandle代替LoadLibrary。同样,如果你想在ThreadFunc中调 用你自己的函数,那么就分别复制这些函数到远程进程并通过INJDATA把地址提供给ThreadFunc。
2. 不要使用static字符串。把所有的字符串提供INJDATA传递。为什么?编译器会把所有的静态字符串放在可执行文件的“.data”段,而仅仅在代 码中保留它们的引用(即指针)。这样,远程进程中的ThreadFunc就会执行不存在的内存数据(至少没有在它自己的内存空间中)。
3. 去掉编译器的/GZ编译选项。这个选项是默认的(看附录B)。
4. 要么把ThreadFunc和AfterThreadFunc声明为static,要么关闭编译器的“增量连接(incremental linking)”(看附录C)。
5. ThreadFunc中的局部变量总大小必须小于4k字节(看附录D)。注意,当degug编译时,这4k中大约有10个字节会被事先占用。
6. 如果有多于3tch分支的case语句,必须像下面这样分割开,或用if-else if代替.
case constant1: statement1; goto END;
case constant2: statement2; goto END;
case constant3: statement2; goto END;
}
case constant5: statement5; goto END;
case constant6: statement6; goto END;
}
END:
kernel32
GetProcAddress 函数功能描述:
GetProcAddress函数检索指定的动态链接库(DLL)中的输出库函数地址。
函数原型:
FARPROC GetProcAddress(
HMODULE hModule, // DLL模块句柄
LPCSTR lpProcName // 函数名
);
参数:
hModule
[in] 包含此函数的DLL模块的句柄。LoadLibrary或者GetModuleHandle函数可以返回此句柄。
lpProcName
[in] 包含函数名的以NULL结尾的字符串,或者指定函数的序数值。如果此参数是一个序数值,它必须在一个字的底字节,高字节必须为0。
返回值:
如果函数调用成功,返回值是DLL中的输出函数地址。
如果函数调用失败,返回值是NULL。得到进一步的错误信息,调用函数GetLastError。
注释:
GetProcAddress函数被用来检索在DLL中的输出函数地址。
lpProcName指针指向的函数名,拼写和大小写必须和DLL源代码中的模块定义文件(.DEF)中输出段(EXPORTS)中指定的相同。 Win32 API函数的输出名可能不同于你在代码中调用的这些函数名,这个不同被宏隐含在相关的SDK头文件中。如果想得到更多信息,请参考Win32函数原型 (Win32 Function Prototypes)。
lpProcName参数能够识别DLL中的函数,通过指定一个与函数相联系的序数值(在.DEF中的EXPORTS段)。 GetProcAddress函数验证那个指定的序数值是否在输出的序数1和最高序数值之间(在.DEF中)。函数用这个序数值作为索引从函数表中读函数 地址,假如.DEF 文件不连续地定义函数的序数值,如从1到N(N是输出的函数序数值),错误将会发生,GetProcAddress将会返回一个错误的、非空的地址,虽然 指定的序数没有对应的函数。
为了防止函数不存在,函数应该通过名字指定而不是序数值。
要求:
Windows NT/2000: 要求Windows NT 3.1 或以后版本。
Windows 95/98: 要求Windows 95 或以后版本。
头文件: 在Winbase.h中声明,include Windows.h。
库文件: Use Kernel32.lib。
参看:
动态链接库纵览(Dynamic-Link Libraries Overview), 动态链接库函数(Dynamic-Link Library Functions),FreeLibrary, GetModuleHandle, LoadLibrary
示例代码:
调用KERNEL32.DLL中的RegisterServiceProcess(仅在Windows98中适用)
HMODULE hModule=GetModuleHandle("kernel32.dll");
if (hModule)
{
typedef DWORD (CALLBACK *LPFNREGISTER)(DWORD,DWORD);
LPFNREGISTER lpfnRegister;
lpfnRegister=(LPFNREGISTER)GetProcAddress(hModule,"RegisterServiceProcess");
if (lpfnRegister)
{
(*lpfnRegister)(NULL,1L);
}
}