c - 变质示例代码

标签 c gcc assembly macros inline

因此,我一直致力于实现来自 James Holderness 的变质代码示例:Metamorphic Code Examples .

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>

#define PUSH 0x50
#define POP 0x58
#define MOV 0xB8
#define NOP 0x90

#define ADD 0x01
#define AND 0x21
#define XOR 0x31
#define OR  0x09
#define SBB 0x19
#define SUB 0x29

#define JUNK asm __volatile__(PUSH,NOP,NOP,NOP,NOP,NOP,NOP,NOP,NOP,POP)
#define JUNKLEN 8

const unsigned char prefixes[] = {ADD, AND, XOR, OR, SBB, SUB, 0};
unsigned char *code;
int codelen;

void readCode(const char *filename)
{
    FILE *fp = fopen(filename, "rb");       JUNK;
    fseek(fp, 0L, SEEK_END);            JUNK;
    codelen = ftell(fp);
    code = malloc(codelen);             JUNK;
    fseek(fp, 0L, SEEK_SET);
    fread(code, codelen, 1, fp);            JUNK;
}

void writeCode(const char *filename)
{
    FILE *fp;
    int lastOffset = strlen(filename) - 1;
    char lastChar = filename[lastOffset];
    char *newFileName = strdup(filename);       JUNK;
    lastChar = '0' + (isdigit(lastChar)?(lastChar - '0' + 1) %10:0);
    newFileName[lastOffset] = lastChar;
    fp = fopen(newFileName, "wb");          JUNK;
    fwrite(code, codelen, 1, fp);           JUNK;
    fclose(fp);
    free(newFileName);
}

int writeInstruction(unsigned reg, int offset, int space)
{
    if (space < 2) {
        code[offset] = NOP;         JUNK;
        return 1;
    } else if (space < 5 || rand() % 2 == 0) {
        code[offset] = prefixes[rand() % 6];    JUNK;
        code[offset + 1] = 0xC0 + rand() % 8 * 8 + reg; JUNK;
        return 2;
    } else {
        code[offset] = MOV + reg;       JUNK;
        *(short *)(code + offset + 1) = rand();
        *(short *)(code + offset + 3) = rand(); JUNK;
        return 5;
    }
}

int readInstruction(unsigned reg, int offset)
{
    unsigned c1 = code[offset];
    if (c1 == NOP)
        return 1;               JUNK;
    if (c1 == MOV + reg)
        return 5;               JUNK;
    if (strchr(prefixes, c1)) {
        unsigned c2 = code[offset + 1];     JUNK;
        if (c2 >= 0xC0 && c2 <= 0xFF && (c2 & 7) == reg)
            return 2;           JUNK;
    }                       JUNK;
    return 0;
}

void replaceJunk(void)
{
    int i, j, inc, space;
    srand(time(NULL));              JUNK;

    for (i = 0; i < codelen - JUNKLEN - 2; i++) {
        unsigned start = code[i];
        unsigned end = code[i + JUNKLEN + 1];
        unsigned reg = start - PUSH;

        if (start < PUSH || start >= PUSH + 8)
            continue;           JUNK;
        if (end != POP + reg)
            continue;           JUNK;
        if (reg == 4)
            continue;

        j = 0;                  JUNK;
        while (inc = readInstruction(reg, i + 1 + j))
            j = j + inc;
        if (j != JUNKLEN)
            continue;           JUNK;

        reg = rand() % 7;           JUNK;
        reg += (reg >= 4);
        code[i] = PUSH + reg;           JUNK;
        code[i + JUNKLEN + 1] = POP + reg;  JUNK;

        space = JUNKLEN;
        j = 0;
        while (space) {
            inc = writeInstruction(reg, i + 1 + j, space);  JUNK;
            j = j + inc;
            space = space - inc;        JUNK;
        }
        printf("%d\n", i);          JUNK;
    }
}

int main(int argc, char *argv[])
{
    readCode(argv[0]);              JUNK;
    replaceJunk();                  JUNK;
    writeCode(argv[0]);             JUNK;

    return 0;
}

我尝试在 Raspbian 4.9 上使用 GCC(版本 6.3.0)进行编译,但编译一直失败并发出错误“undefined reference to __emit__”。现在我知道这是因为 emit 是一个 Borland C 编译器宏,因此我尝试使用此处的 asm volatile 宏(Implementing Borland's __emit__ macro in GCC)来实现类似的功能。

如何更改代码以使用 GCC?我尝试了 asm volatile 的多种不同用途,但似乎没有任何效果。我预计大多数 #defines 都必须更改,我只是不知道正确的方法。

最佳答案

您可以使用 .byte 指令将任意字节放在 asm block 的位置,如下所示:

asm __volatile__(".byte 0x50, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x58\n");

这是一个 live example on godbolt ,包括最右边的 Pane ,它显示它很好地反编译成一个 push rax、八个 noppop rax

查看更多关于 .byte 指令的信息 here .

但是,这在 Raspberry Pi 上仍然不起作用,因为操作码似乎适用于 x86。您必须将它们更改为相应的 ARM 操作码。此外,GCC 是一个高度优化的编译器,您不能像这段代码在旧的 Borland C 编译器上那样操作 C 堆栈。

关于c - 变质示例代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46802894/

相关文章:

c - 错误 : c:87:(. 文本+0x247):重定位被截断以适合:针对 undefined symbol `course_insert' 的 R_X86_64_PC32

c++ - 使用不支持 GNU C 打包结构的 Digital Mars 编译器获取 VESA 视频信息

c - 是否可以访问LR、PC等CPU寄存器

linux - 在现代 Linux x86-64 中,用户空间覆盖 GS 寄存器是否安全?

c - 从 xml 响应中提取 url

c++ - 访问违规写入位置,在我的循环中

c++ - 是否可以显式特化模板以匹配 lambda?

c - 忽略包含文件时,拆分源没有输出,但也没有警告

c - 打印时我的二维数组中缺少一个元素

c++ - GCC 将私有(private)继承转换为父级