Remcos分析报告

admin 2024年1月10日12:30:52评论12 views字数 5728阅读19分5秒阅读模式
程序开始会动态获取函数地址
Remcos分析报告

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

Remcos分析报告
Remcos分析报告

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

Remcos分析报告
Remcos分析报告

创建互斥体,名为Rmc-ALXH27

Remcos分析报告

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

Remcos分析报告

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

Remcos分析报告

加密后

Remcos分析报告

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

Remcos分析报告
Remcos分析报告
Remcos分析报告

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

Remcos分析报告
Remcos分析报告
Remcos分析报告

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

Remcos分析报告
Remcos分析报告

记录键盘操作的文件

Remcos分析报告

获取用户的信息

Remcos分析报告

禁用DEP 数据执行保护

Remcos分析报告

检查当前运行的权限

Remcos分析报告
Remcos分析报告

加载ws2_32.dll

Remcos分析报告

循环分别获取 getaddrinfo getnameinfo freeaddrinfo

Remcos分析报告

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

Remcos分析报告

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

Remcos分析报告

发送加密后的数据

Remcos分析报告

读取服务器发来的数据

Remcos分析报告

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

Remcos分析报告

远控指令如下:

指令 功能
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规则:

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("rnrn");

}
void DataDispose(char* Data, unsigned long Len)
{
 int temp = 0;
 int temp1 = 0;
 for (int i = 0;i < Len - 1;i++)
 {
  if (Data[i] == '')
  {
   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 ] = '';
 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;
}

Remcos分析报告

原文始发于微信公众号(红队蓝军):Remcos分析报告

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年1月10日12:30:52
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Remcos分析报告http://cn-sec.com/archives/2378941.html

发表评论

匿名网友 填写信息