자체 수정 x86_64 머신 코드, 123 바이트
0f b6 0f 31 c0 eb 11 0f be c9 8d 04 80 8d 44 41 d0 0f b6 4f 01 48 ff c7 83 f9 21 75 ea b9 21 21 21 a1 33 0f 0f bc c9 81 c1 ff 07 00 00 c1 e9 03 0f b6 c9 89 ca 09 c2 74 35 55 48 89 e5 c7 45 fc 59 58 5c 5e 8a 4c 0d fc 88 0d 15 00 00 00 f3 0f 2a c8 83 f8 02 5d 7c 1f ff c8 0f 57 c0 f3 0f 2a c0 f3 0f 5e c1 83 f8 01 0f 28 c8 7f eb c3 f3 0f 10 05 03 01 00 00 c3 0f 28 c1 c3
해석 된 언어가 화려한 코드를 동적으로 실행할 수있는 이유 eval
일반 머신 코드가 아닌 입니까?
그것을 사용해보십시오 :
#include <stdio.h>
#include <sys/mman.h>
#include <errno.h>
char ff[] = "\x0f\xb6\x0f\x31\xc0\xeb\x11\x0f\xbe\xc9\x8d\x04\x80\x8d\x44\x41\xd0\x0f\xb6\x4f\x01\x48\xff\xc7\x83\xf9\x21\x75\xea\xb9\x21\x21\x21\xa1\x33\x0f\x0f\xbc\xc9\x81\xc1\xff\x07\x00\x00\xc1\xe9\x03\x0f\xb6\xc9\x89\xca\x09\xc2\x74\x35\x55\x48\x89\xe5\xc7\x45\xfc\x59\x58\x5c\x5e\x8a\x4c\x0d\xfc\x88\x0d\x15\x00\x00\x00\xf3\x0f\x2a\xc8\x83\xf8\x02\x5d\x7c\x1f\xff\xc8\x0f\x57\xc0\xf3\x0f\x2a\xc0\xf3\x0f\x5e\xc1\x83\xf8\x01\x0f\x28\xc8\x7f\xeb\xc3\xf3\x0f\x10\x05\x03\x01\x00\x00\xc3\x0f\x28\xc1\xc3";
int main()
{
char* page = (char*)((unsigned long)((char*)ff) & (~0xfffLL));
if (mprotect(page, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC) < 0) {
perror("mprotect");
return -1;
}
float (*f)(char*) = (float (*)(char*))ff;
char* testcases[] = { "0!","1!","2!","3!","4!","5!","6!","7!","8!","9!","10!",
"0!!","1!!","2!!","3!!","4!!","5!!","6!!","7!!","8!!","9!!","10!!",
"0!!!","1!!!","2!!!","3!!!","4!!!","5!!!","6!!!","7!!!","8!!!","9!!!","10!!!",
"0!!!!","1!!!!","2!!!!","3!!!!","4!!!!","5!!!!","6!!!!","7!!!!","8!!!!","9!!!!","10!!!!",
};
for (int i = 0; i < 44; i++) {
printf("%s -> %f\n", testcases[i], f(testcases[i]));
}
}
어셈블리:
_f:
100000d4f: 0f b6 0f movzx ecx, byte ptr [rdi]
100000d52: 31 c0 xor eax, eax
100000d54: eb 11 jmp 17 <_f+18>
100000d56: 0f be c9 movsx ecx, cl
100000d59: 8d 04 80 lea eax, [rax + 4*rax]
100000d5c: 8d 44 41 d0 lea eax, [rcx + 2*rax - 48]
100000d60: 0f b6 4f 01 movzx ecx, byte ptr [rdi + 1]
100000d64: 48 ff c7 inc rdi
100000d67: 83 f9 21 cmp ecx, 33
100000d6a: 75 ea jne -22 <_f+7>
100000d6c: b9 21 21 21 a1 mov ecx, 2703302945
100000d71: 33 0f xor ecx, dword ptr [rdi]
100000d73: 0f bc c9 bsf ecx, ecx
100000d76: 81 c1 ff 07 00 00 add ecx, 2047
100000d7c: c1 e9 03 shr ecx, 3
100000d7f: 0f b6 c9 movzx ecx, cl
100000d82: 89 ca mov edx, ecx
100000d84: 09 c2 or edx, eax
100000d86: 74 35 je 53 <_f+6E>
100000d88: 55 push rbp
100000d89: 48 89 e5 mov rbp, rsp
100000d8c: c7 45 fc 59 58 5c 5e mov dword ptr [rbp - 4], 1583110233
100000d93: 8a 4c 0d fc mov cl, byte ptr [rbp + rcx - 4]
100000d97: 88 0d 15 00 00 00 mov byte ptr [rip + 21], cl
100000d9d: f3 0f 2a c8 cvtsi2ss xmm1, eax
100000da1: 83 f8 02 cmp eax, 2
100000da4: 5d pop rbp
100000da5: 7c 1f jl 31 <_f+77>
100000da7: ff c8 dec eax
100000da9: 0f 57 c0 xorps xmm0, xmm0
100000dac: f3 0f 2a c0 cvtsi2ss xmm0, eax
100000db0: f3 0f 5e c1 divss xmm0, xmm1
100000db4: 83 f8 01 cmp eax, 1
100000db7: 0f 28 c8 movaps xmm1, xmm0
100000dba: 7f eb jg -21 <_f+58>
100000dbc: c3 ret
100000dbd: f3 0f 10 05 03 01 00 00 movss xmm0, dword ptr [rip + 259]
100000dc5: c3 ret
100000dc6: 0f 28 c1 movaps xmm0, xmm1
100000dc9: c3 ret
나중에 설명이 추가됩니다. 기본적인 아이디어는 수정하는 것입니다 divss xmm0, xmm1
에서 지시를 0x100000db0
하고로 교체 mulss
,addss
, subss
또는divss
제공된 피연산자에 따라. 입력 문자열을 구문 분석하는 데 작은 트릭도 사용됩니다.
다음으로 생성 된 어셈블리 :
float f (char* s)
{
int x;
for (x=0; *s != '!'; s++) {
x=10*x + (*s-'0');
}
unsigned char op = (__builtin_ctz(*(unsigned int *)s ^ 0xa1212121)-1) >> 3;
if (x == 0 && op == 0) {
return 1;
}
unsigned int lookup = 0x5e5c5859;
unsigned char new_code = ((unsigned char*)&lookup)[op];
asm("movb %0, 0x15(%%rip)" : : "r" (new_code));
float sum;
for (sum = x--; x>0; x--) {
sum = x / sum;
}
return sum;
}