如何使用CODASM编码Payload并降低熵值

2024-09-18 8 0

关于CODASM

CODASM是一款针对Payload的编码工具,该工具针对红蓝队研究人员设计,可以帮助我们对Payload执行编码操作并显著降低Payload的熵值。

该工具允许您将任意数据编码为伪 ASM 指令,并将其编译到二进制文件的 .text 部分。

开销为 80-120%(例如 380KB CS shellcode => 870KB CODASM 有效负载)。

功能介绍

Payload(尤其是 shellcode)具有相当高的熵,在编译后的二进制文件中的大多数位置看起来都不合适。CODASM 旨在将Payload隐藏在已经具有高熵的位置:.text包含二进制文件编译代码的部分。为此,CODASM 将生成良性 shellcode,并支持嵌入任意Payload。

CODASM 是一个 Python 脚本,可以生成以下内容:

1、良性的 shellcode,用于任意Payload;

2、一个 C 头文件,你可以在程序中使用它将 shellcode 嵌入到二进制文件中,并在运行时检索它;

对于编码Payload,CODASM 执行以下操作:

1、生成有效 x86_64 函数;

2、将Payload字节嵌入到指令操作数中(例如mov eax, <4 bytes of payload>);

3、对嵌入的Payload字节进行异或加密;

为了解码Payload,生成的 C 头文件执行以下操作:

1、解析单个指令,直到检索到所需数量的Payload字节:

2、检测单个指令,确定它们是否包含Payload字节;

3、如果指令包含Payload字节,则提取并解密它们;

工具要求

Python 3

工具安装

由于该工具基于Python 3开发,因此我们首先需要在本地设备上安装并配置好最新版本的Python 3环境。

接下来,广大研究人员可以直接使用下列命令将该项目源码克隆至本地:

git clone https://github.com/NVISOsecurity/codasm

工具使用

usage: codasm.py [-h] -i INPUT [-oa OUT_ASM] [-ob OUT_BIN] [-oc OUT_C] [-op OUT_P] [--rng RNG] [-vbmin VAL_BYTES_MIN] [-vbmax VAL_BYTES_MAX] [-vbch VAL_BYTES_CHANCE] [-v]

 

CODASM encoding utility

 

options:

  -h, --help           显示此帮助消息并退出

  -i INPUT, --input INPUT

                        要编码为ASM/二进制指令的输入文件的路径

  -oa OUT_ASM, --out-asm OUT_ASM

                        将生成的ASM指令写入的路径

  -ob OUT_BIN, --out-bin OUT_BIN

                       将生成的二进制指令写入的路径

  -oc OUT_C, --out-c OUT_C

                        将生成的CODASM解码器写入的路径

  -op OUT_P, --out-p OUT_P

                        将嵌入式Payload写入的路径

  --rng RNG     用于随机化的rng种子(异或密钥、有效载荷指令顺序、解码操作顺序)

  -vbmin VAL_BYTES_MIN, --val-bytes-min VAL_BYTES_MIN

                        编码到单个方法中的最小字节数(默认值64)

  -vbmax VAL_BYTES_MAX, --val-bytes-max VAL_BYTES_MAX

                        编码到单个方法中的最大字节数(默认256)

  -vbch VAL_BYTES_CHANCE, --val-bytes-chance VAL_BYTES_CHANCE

                        操作成为编码数据而不是虚拟数据的机会(0.1-0.9,默认值0.1)

  -v, --verbose   输出详细程度(0-3,默认值0)

 

Note: ASM output is meant to be used for manual reference, not for compiling!

使用样例

1、准备 shellcode (例如 CS/BR shellcode) 并另存为shellcode.bin;

2、使用 CODASM 对 shellcode 进行编码:

./codasm.py --i shellcode.bin -oc codasmloader.h

3、复制codasmloader.h到您最喜欢的加载器或独立的最小加载器中(例如/demo/codasm.c);

4、确保decode在调用 shellcode 之前调用 CODASM:

/* ~snip CODASM decode~*/

 

#include <stdlib.h>

 

// "INTEXT" macro ensures that the payload is pleced into the `.text` section

INTEXT uint8_t payload[5978] = {

    0x50, 0x53, 0x51, 0x52, 0x41, 0x50, 0x41, 0x51, 0x41, 0x52, 0x41, 0x53, /* ... */

};

 

int main() {

    uint64_t xor_key = 0xFFFDA6803A51E3FB; // Generated by CODASM

    uint8_t* input = (uint8_t*)payload;

    uint8_t* output = (uint8_t*)malloc(sizeof(payload));

    uint32_t output_length = 0xac4;

    int32_t res = 0;

    if ((res = decode(input, sizeof(payload), output, output_length, xor_key)) < 0)

        return 1; // Some doo-doo happened, investigate value of res

    // You successfully recovered the payload, do something fun with it here :)

    return 0;

}

5、编译你的加载器;

6、确保生成的二进制文件删除所有调试信息;

工具运行演示

# Input file

$ cat test.txt

my secret message

 

# Encode & generate C file

$ ./codasm.py -i test.txt -ob test.bin -oa test.asm -oc test.c

 

# Generated mashine code

$ xxd test.bin

00000000: 5053 5152 4150 4151 4152 4153 4154 4155  PSQRAPAQARASATAU

00000010: 4156 4157 4883 ec28 751b 757f c705 5696  AVAWH..(u.u...V.

00000020: 44e9 6df6 61d6 84c0 488d 0d91 9e02 2640  D.m.a...H.....&@

00000030: 32ff b91b 8052 f975 8283 f99c 85c9 7513  2....R.u......u.

00000040: 4883 c428 415f 415e 415d 415c 415b 415a  H..(A_A^A]A\A[AZ

00000050: 4159 4158 5a59 5b68 c3cc                 AYAXZY[X..

 

# Generated ASM

$ cat test.asm

push rax

...

push r15

sub RSP, 0x28

jnz 0x1B

jnz 0x7F

mov 0xE9449656,0xD661F66D

test al,al

lea 0x26029E91

xor dil,dil

mov ecx,0xF952801B

jnz 0x82

cmp ecx,0x9C

test ecx,ecx

jnz 0x13

add RSP, 0x28

pop r15

...

pop rax

retn

; Padding

 

# Prepare generated C file for compilation

$ sed -i "s/\/\* Generated.*//" test.c

$ sed -i "s/Sample usage://" test.c

$ sed -i "s/}\*\//}/" test.c

 

# Minimal program in C file:

$ tail -n 30 test.c

 

#endif // CODASM_DECODE

 

 

   

 

#include <stdlib.h>

 

INTEXT uint8_t payload[90] = {

    0x50, 0x53, 0x51, 0x52, 0x41, 0x50, 0x41, 0x51, 0x41, 0x52, 0x41, 0x53, /* ... */

 

int main() {

    uint64_t xor_key = 0xFBE38A21E5760676;

    uint8_t* input = (uint8_t*)payload;

    uint8_t* output = (uint8_t*)malloc(sizeof(payload));

    uint32_t output_length = 0x11;

    int32_t res = 0;

    if ((res = decode(input, sizeof(payload), output, output_length, xor_key)) < 0)

        return 1; // Some doo-doo happened, investigate value of res

    // You successfully recovered the payload, do something fun with it here :)

    return 0;

}

 

# Compile using MINGW

$ x86_64-w64-mingw32-gcc test.c -o test.exe

 

# Find generated ASM in compiled EXE:

$ objdump -d test.exe

 

...

0000000140002da0 <payload>:

   140002da0: 50                    push   %rax

   ...

   140002db2: 41 57                 push   %r15

   140002db4: 48 83 ec 28           sub    $0x28,%rsp

   140002db8: 75 1b                 jne    140002dd5 <payload+0x35>

   140002dba: 75 7f                 jne    140002e3b <main+0x41>

   140002dbc: c7 05 56 96 44 e9 6d movl   $0xd661f66d,-0x16bb69aa(%rip)        # 12944c41c <__size_of_stack_reserve__+0x12924c41c>

   140002dc3: f6 61 d6

   140002dc6: 84 c0                 test   %al,%al

   140002dc8: 48 8d 0d 91 9e 02 26 lea    0x26029e91(%rip),%rcx        # 16602cc60 <.debug_ranges+0x25fde970>

   140002dcf: 40 32 ff              xor    %dil,%dil

   140002dd2: b9 1b 80 52 f9        mov    $0xf952801b,%ecx

   140002dd7: 75 82                 jne    140002d5b <decode+0x4f>

   140002dd9: 83 f9 9c              cmp    $0xffffff9c,%ecx

   140002ddc: 85 c9                 test   %ecx,%ecx

   140002dde: 75 13                 jne    140002df3 <payload+0x53>

   140002de0: 48 83 c4 28           add    $0x28,%rsp

   140002de4: 41 5f                 pop    %r15

   ...

   140002df7: 58                    pop    %rax

   140002df8: c3                    ret    

   140002df9: cc                    int3

...

嵌入的payload在IDA中如下所示:

检测

您可以使用以下 YARA 规则来潜在地检测嵌入 CODASM 生成的输出的 PECOFF 文件。您可以在代码块下方找到规则的简要说明:

import "pe"

import "math"

 

 

private rule IsPE

{

    meta:

        description = "Tests whether the file starts with the MZ header."

        author = "Moritz Thomas"

        date = "2024-07-24"

 

    condition:

        uint16(0) == 0x5A4D

}

 

private rule ExampleUsage

{

    meta:

        description = "Detects malloc and invoking the decode function, passing in references to the .data section"

        author = "Moritz Thomas"

        date = "2024-07-24"

    

    strings:

        $AllocDecode = {

            8b 0d ?? ?? ?? ??   // MOV ECX, dword ptr [DAT_1400fb070]

            89 4c 24 ??         // MOV dword ptr [RSP + 0x3c], ECX

            e8 ?? ?? ?? ??      // CALL MSVCRT.DLL::malloc

                               // ECX = DAT_1400fb070

                               // [RSP + 0x3c] = ECX

                               // malloc()

            8b 15 ?? ?? ?? ??   // MOV EDX, dword ptr [DAT_1400fb080]

            44 8b 4c 24 ??      // MOV R9D, dword ptr [RSP + 0x3c]

                               // EDX = DAT_1400fb080

                               // R9D = [RSP + 0x3c]

            48 8d 0d ?? ?? ?? ?? // LEA RCX, [FUN_140001460]

            48 89 c3            // MOV RBX, RAX

            48 8b 05 ?? ?? ?? ?? // MOV RAX, qword ptr [DAT_1400fb090]

            49 89 d8            // MOV R8, RBX

            48 89 44 24 ??      // MOV qword ptr [RSP + 0x20], RAX

                               // RCX = &FUN_140001460

                               // RBX = RAX

                               // RAX = DAT_1400fb090

                               // R8 = RBX

                               // [RSP + 0x20] = RAX

            e8 ?? ?? ?? ??      // CALL FUN_1400f9cf0

                               // FUN_1400f9cf0()

            89 c2               // MOV EDX, EAX

            85 c0               // TEST EAX, EAX

            79 13               // JNS LAB_1400fac7b

                               // EDX = EAX

                               // if (EAX >= 0) goto LAB_1400fac7b

            48 8d 0d ?? ?? ?? ?? // LEA RCX, [LAB_1400fc0e3]

            e8 ?? ?? ?? ??      // CALL FUN_1400faae0

                               // RCX = &LAB_1400fc0e3

                               // FUN_1400faae0()

            b8 01 00 00 00      // MOV EAX, 0x1

            eb ??               // JMP !AB_1400faca3

                               // EAX = 1

                               // goto LAB_1400faca3

            83 f8 42            // CMP EAX, 0x42

            75 ??               // JNZ LAB_1400fac8a

                               // if (EAX != 0x42) goto LAB_1400fac8a

            b9 22 00 00 00      // MOV ECX, 0x22

            e8 ?? ?? ?? ??      // CALL FUN_140001460

                               // ECX = 0x22

                               // FUN_140001460()

        }

        // if (iVar2 == 0x42) FUN_140001460(0x22, 0x42);

        $PseudoCall= {

            83 f8 42          // CMP EAX, 0x42

            75 ??             // JNZ LAB_1400FACA3

            b9 22 00 00 00    // MOV ECX, 0x22

            e8 ?? ?? ?? ??    // CALL FUN_140001460

        }

 

    condition:

        IsPE and $AllocDecode and $PseudoCall

}

 

private rule Decode

{

    meta:

        description = "Detects parameter validation (null-checks), returning -2 and performing a pseudo call RBX(22h)"

        author = "Moritz Thomas"

        date = "2024-07-24"

    

    strings:

        $NullTest = {

            48 85 c9 // TEST    param_1,param_1

            74 ??    // JZ      LAB_1400f9d76

            4d 85 c0 // TEST    param_3,param_3

            74 ??    // JZ      LAB_1400f9d76

        }

        $ReturnMinusTwo = {

            b8 fe ff ff ff  // MOV  EAX,0xfffffffe

        }

        $PseudoCall = {

            b9 22 00 00 00  // MOV  ECX,0x22

            ff d3           // CALL RBX

        }

 

    condition:

        IsPE and $NullTest and $ReturnMinusTwo and $PseudoCall

}

 

private rule PEAnalysis

{

    meta:

        description = "Detects PE files with very large .text sections (>=90%) that have reasonable entropy (5.0 < e(.text) < 7.0)."

        author = "Moritz Thomas"

        date = "2024-07-24"

 

    condition:

        IsPE and // Check for MZ header

        for any i in (0..pe.number_of_sections - 1) : (

            pe.sections[i].name == ".text"  and

            pe.sections[i].raw_data_size > (filesize * 0.9) and

            math.in_range(

                math.entropy(pe.sections[i].raw_data_offset, pe.sections[i].raw_data_size),

                5.0, 7.0

            )

            

        )

}

 

rule CODASMed

{

    condition:

        ExampleUsage or (Decode and PEAnalysis)

}

许可证协议

本项目的开发与发布遵循MIT开源许可协议。

项目地址

CODASM:【GitHub传送门

参考资料

https://www.nviso.eu/


4A评测 - 免责申明

本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。

不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。

本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。

如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!

程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。

侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)

相关文章

苹果试图保护你的隐私,OpenAI可能做不到
Shuffle:一款完全自动化的安全栈增强平台
SessionExec:一款针对会话安全的安全命令测试工具
Arkime:一款大规模数据包捕获和索引数据库系统
从蓝队流量角度分析Shiro-550反序列化漏洞
万字长文浅谈三高系统建设方法论和实践

发布评论