所以我一直在努力实现James Holderness的变形代码示例:Metamorphic Code Examples。
public void Test()
{
AppLog.Logger = Substitute.For<ILogger>(); // NSubstitute
var logMock = new Mock<ILogger>(); // Moq
AppLog.Logger = logMock.Object; // Moq
SomeMethodToTest();
AppLog.Logger.Recieved(1).LogSomething(...); // NSubstitute
logMock.Verify(x => x.LogSomething(...)); // Moq
}
我正在尝试使用Raspbian 4.9上的GCC(版本6.3.0)进行编译,但编译仍然失败并发出错误“未定义引用#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;
}
。现在我知道这是因为 emit 是一个Borland C编译器宏,因此我尝试使用此处找到的asm volatile 宏来实现类似的功能(Implementing Borland's __emit__ macro in GCC)。
如何更改代码以使用GCC?我已尝试过asm volatile 的多种不同用途,但似乎没有任何效果。我希望大多数#defines都必须改变,我只是不知道正确的方法。
答案 0 :(得分:3)
您可以使用asm
指令将任意字节放在.byte
块的位置,如下所示:
asm __volatile__(".byte 0x50, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x58\n");
此处&#39; sa live example on godbolt,包括最右边的窗格,显示它已正确反编译为push rax
,8 nop
和pop rax
。
详细了解.byte
指令here。
然而,这仍然不适用于Raspberry Pi,因为操作码似乎适用于x86。您必须将它们更改为相应的ARM操作码。此外,GCC是一个高度优化的编译器,你不能像使用旧的Borland C编译器那样操作C堆栈。