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

Remcos分析报告

作者头像
红队蓝军
发布2024-01-11 15:03:18
1320
发布2024-01-11 15:03:18
举报
文章被收录于专栏:红队蓝军红队蓝军

程序开始会动态获取函数地址

获取资源文件,通过RC4算法解密配置,获取 C2 服务器信息,注册表中的子键名称,木马功能的配置 licence内容等信息,互斥体名称 中间以 "丨" 分隔

内嵌了样本的版本号 此版本为remcos的最新版本 发布自2022/8/21

创建互斥体,名为Rmc-ALXH27

判断是否是64位程序,打开注册表,查询产品名称,最后返回 计算机信息(windows7 Ultimate 32bit)

通过RC4算法加密原样本的所在路径

加密后

将加密后的样本路径存放到注册表中 创建注册表键 键名为exepath

从资源段的解密的配置中返回916F25041F4C7DA3515196E496E1F826 创建注册表键,键名为licence

创建线程,记录键盘消息,线程回调,创建文件C:\ProgramData\remcos\logs.dat, 并写入当前时间,并使用 API SetWindowsHookExA 创建线程设置消息钩子,记录键盘鼠标的操作

记录键盘操作的文件

获取用户的信息

禁用DEP 数据执行保护

检查当前运行的权限

加载ws2_32.dll

循环分别获取 getaddrinfo getnameinfo freeaddrinfo

调用getaddrinfo函数根据ip地址和端口号获取sockaddr结构

利用sockaddr结构初始化socket和创建事件对象

发送加密后的数据

读取服务器发来的数据

创建线程 处理接收到的数据

远控指令如下:

指令

功能

0x92

设置受感染主机桌面图片风格

0x94

修改指定窗口的标题

0x95

获得当前可用的物理和虚拟内存信息

0x97

通过dixdiag诊断工具获取系统信息

0x98

向C&C服务器上传文件或从C&C服务器下载文件

0x9E 0xA2

在%temp%下创建alarm.wav文件 并播放声音

0xAC

在受感染的机器上弹出窗口

0x1

获取受感染主机最顶端程序标题

0x3

收集受感染主机所有已安装软件的相关信息 包括其软件供应商信息、版本信息、安装的路径信息、安装的日期、卸载字符串等

0x6

收集受感染主机所有正在运行的进程信息

0x7

结束指定进程

0x8

枚举窗口

0x9

关闭指定窗口

0xA 0xB

显示/隐藏指定窗口

0xC

获取指定窗口的PID

0xD

执行指定命令行命令

0xF

可打开 文件,文件夹,网址等等

0x10

获取屏幕截图

0x11

关闭连接

0x12

获取键盘信息

0x13

启动在线键盘记录器

0x14

停止在线键盘记录器

0x15 0x16

读取指定文件并发送到C2

0x17

删除指定文件

0x18

清除IE、Firefox、Chrome等浏览器的登陆信息和cookie信息

0x1B

控制受感染设备摄像头

0x1D

开始录音

0x1E

停止录音

0x20

删除指定文件

0x21

退出进程

0x22

清理自身在受感染机器上留下的痕迹

0x23

执行vbs脚本“caonvgbpgsuqbxegcnjfxv.vbs”来重启自身

0x24 0x25

下载数据并执行还会清除自身在用户机的痕迹

0x26

通过MessageBoxW函数弹窗显示信息

0x27

关闭系统,重启,注销用户

0x28

获取用户剪切板数据

0x29 0x2A

清除剪切板内容

0x2B

创建一个共享内存来共享数据

0x2C

从指定的URL下载数据并将数据共享到创建的共享内存中

0x31

在注册表中保存用户名

YARA规则:

代码语言:javascript
复制
rule Remcos
{
 strings:
  $my_hex_string  = {46 8B 44 B4 10 03 F8 81 E7 FF 00 00 80 79 08 4F 81 CF 00 FF FF FF 47}
  $my_hex_string1  = {25 30 32 69 3A 25 30 32 69 3A 25 30 32 69 3A 25 30 33 69}
  $my_string1 = "SETTINGS"
 condition:
  $my_hex_string and $my_hex_string1 and $my_string1
}

配置提取工具:
// ConfigExtract.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <Windows.h>
#include <vector>
using namespace std;
void rc4_init(unsigned int* s, unsigned char* key, unsigned long Len) //初始化函数
{
 int i = 0, j = 0;
 char k[256] = { 0 };
 unsigned char tmp = 0;
 for (i = 0;i < 256;i++)
 {
  s[i] = i;
  k[i] = key[i % Len];
 }
 for (i = 0; i < 256; i++)
 {
  j = (j + s[i] + k[i]) % 256;
  tmp = s[i];
  s[i] = s[j]; //交换s[i]和s[j]
  s[j] = tmp;
 }
}

std::vector<string> split(const string& str, char pattern)
{
 char* strc = new char[strlen(str.c_str()) + 1];
 strcpy(strc, str.c_str());
 std::vector<string> resultVec;
 char* tmpStr = strtok(strc, &pattern);
 while (tmpStr != NULL)
 {
  resultVec.push_back(string(tmpStr));
  tmpStr = strtok(NULL, &pattern);
 }
 delete[] strc;

 return resultVec;
}
void print(const char* key, const char* value)
{
 if (value[0] == 0x1e)
 {
  return;
 }
 printf("%s: ", key);
 for (int i = 0; i < strlen(value); i++)
 {
  if (value[i] == 0x1e)
  {
   continue;
  }
  printf("%c", value[i]);
 }
 printf("\r\n\r\n");

}
void DataDispose(char* Data, unsigned long Len)
{
 int temp = 0;
 int temp1 = 0;
 for (int i = 0;i < Len - 1;i++)
 {
  if (Data[i] == '\0')
  {
   Data[i] = 0x1e;
  }
  if (Data[i] == 0x7c)
  {
   temp++;
  }
  else if (Data[i] == 0x40)
  {
   temp1++;
  }
 }
 char c;
 temp > temp1 ? c = '|' : c = '@';
 vector<string> config;
 config = split(Data,c);

 //判断是哪种分割符号分割的
 if (temp> temp1)
 {
  print("C2", config[0].c_str());
  print("Botnet", config[2].c_str());
  print("copy_file", config[0x13].c_str());
  print("copy_file", config[0x14].c_str());
  print("startup_value", config[0x15].c_str());
  print("startup_value", config[0x16].c_str());
  print("mutex", config[0x1b].c_str());
  print("mutex", config[0x1c].c_str());
  print("keylog_file", config[0x21].c_str());
  print("keylog_file", config[0x22].c_str());
  print("take_screenshot_title", config[0x2d].c_str());
  print("take_screenshot_title", config[0x2e].c_str());
  print("screenshot_folder", config[0x33].c_str());
  print("screenshot_folder", config[0x34].c_str());
  print("audio_folder", config[0x4b].c_str());
  print("audio_folder", config[0x4c].c_str());
  print("copy_folder", config[0x5f].c_str());
  print("copy_folder", config[0x60].c_str());
  print("keylog_folder", config[0x61].c_str());
  print("keylog_folder", config[0x62].c_str());
 }
 else if (temp < temp1)
 {
  print("C2", config[0].c_str());
  print("Botnet", config[1].c_str());
  print("copy_file", config[0xa].c_str());
  print("startup_value", config[0xb].c_str());
  print("mutex", config[0xe].c_str());
  print("keylog_file", config[0x11].c_str());
  print("take_screenshot_title", config[0x19].c_str());
  print("screenshot_folder", config[0x25].c_str());
  print("copy_folder", config[0x2e].c_str());
  print("keylog_folder", config[0x2f].c_str());
 }



}
void rc4_crypt(unsigned int* s, unsigned char* Data, unsigned long Len) //加解密
{
 int i = 0, j = 0, t = 0;
 unsigned long k = 0;
 unsigned char tmp;
 for (k = 0;k < Len;k++)
 {
  i = (i + 1) % 256;
  j = (j + s[i]) % 256;
  tmp = s[i];
  s[i] = s[j]; //交换s[x]和s[y]
  s[j] = tmp;
  t = (s[i] + s[j]) % 256;
  Data[k] ^= s[t];
 }

 DataDispose((char*)Data, Len);
 
}
void decode(char* ResourceData,int resourceSize)
{
 unsigned int s[256] = { 0 };
 char* key = new char[(BYTE)ResourceData[0]];
 memcpy(key, ResourceData + 1, (BYTE)ResourceData[0]);

 char* c = ResourceData + 0x4e;
 rc4_init(s, (unsigned char*)key, (BYTE)ResourceData[0]);   //已经完成了初始化
 rc4_crypt(s, (unsigned char*)(ResourceData+1+ (BYTE)ResourceData[0]), (resourceSize- (1 + (BYTE)ResourceData[0])));//解密
}
int main()
{
 char filePath[256] = { 0 };
 printf("文件路径:");
 scanf_s("%s", filePath, 256);
 int size = strlen(filePath);
 filePath[size] = '.';
 filePath[size + 1 ] = '\0';
 HMODULE hMod = LoadLibraryA(filePath);
 if (hMod == NULL)
 {
  return 0;
 }
 HRSRC hRes = FindResourceA(hMod, "SETTINGS", (LPCSTR)RT_RCDATA);
 if (hRes == NULL)
 {
  return 0;
 }
 HGLOBAL ResData = LoadResource(hMod, hRes);
 int resSize = SizeofResource(hMod, hRes);

 char* pResData = new char[resSize+1];
 memcpy(pResData, ResData, resSize);
 FreeLibrary(hMod);
 decode(pResData, resSize);
 delete[] pResData;
 system("pause");

 return 0;
}
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2024-01-04,如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档