Remcos分析报告

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

Remcos分析报告_第1张图片

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

Remcos分析报告_第2张图片

Remcos分析报告_第3张图片

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

Remcos分析报告_第4张图片

Remcos分析报告_第5张图片

创建互斥体,名为Rmc-ALXH27

Remcos分析报告_第6张图片

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

Remcos分析报告_第7张图片

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

Remcos分析报告_第8张图片

加密后

图片

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

Remcos分析报告_第9张图片

Remcos分析报告_第10张图片

Remcos分析报告_第11张图片

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

Remcos分析报告_第12张图片

Remcos分析报告_第13张图片

Remcos分析报告_第14张图片

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

Remcos分析报告_第15张图片

Remcos分析报告_第16张图片

记录键盘操作的文件

Remcos分析报告_第17张图片

获取用户的信息

Remcos分析报告_第18张图片

禁用DEP 数据执行保护

图片

检查当前运行的权限

图片

Remcos分析报告_第19张图片

加载ws2_32.dll

Remcos分析报告_第20张图片

循环分别获取 getaddrinfo getnameinfo freeaddrinfo

Remcos分析报告_第21张图片

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

Remcos分析报告_第22张图片

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

Remcos分析报告_第23张图片

发送加密后的数据

Remcos分析报告_第24张图片

读取服务器发来的数据

Remcos分析报告_第25张图片

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

Remcos分析报告_第26张图片

远控指令如下:

指令 功能
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 
#include 
#include 
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 split(const string& str, char pattern)
{
 char* strc = new char[strlen(str.c_str()) + 1];
 strcpy(strc, str.c_str());
 std::vector 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 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;
}

你可能感兴趣的:(网络安全)