#一、背景
- 在Linux內核的代碼中,大部分以C內聯彙編編寫。
- 在編寫病毒時,也會常常用到,比如,要編寫一個不依賴libc的注入代碼時,需要調用mmap進行內存申請時,就要使用到syscall進行系統調用。這時就需要使用到C語言的內聯彙編。
static inline volatile int evil_open(const char *path, unsigned long flags)
{
long ret;
__asm__ volatile(
"mov %0, %%rdi\n"
"mov %1, %%rsi\n"
"mov $2, %%rax\n"
"syscall" : : "g"(path), "g"(flags));
asm ("mov %%rax, %0" : "=r"(ret));
return ret;
}
#二、內聯彙編基本格式
asm [ volatile ] (
assembler template 彙編代碼。通常分行編寫
[ : output operands ] /* optional */ 輸出操作數
[ : input operands ] /* optional */ 輸入操作數
[ : list of clobbered registers ] /* optional */ 指定不允許gcc編譯器使用的寄存器列表
);
- 由於避免命名衝突,asm與__asm__等價,volatile 與 __volatile__等價
- volatile 用於指示,當添加此關鍵字時,不允許gcc編譯器對assmbly code進行代碼優化。
- 以上中括號,代表可選參數。也就是可以完全只包含彙編代碼,而不包含,輸入操作數和輸出操作數以及不允許gcc編譯器使用的寄存器列表。
#三、實例
下面的代碼就是使用C語言的內聯彙編,syscall進行系統調用。在屏幕上輸出“I am HotIce0”。並且調用exit(0)退出程序,這是一段可以編譯爲位置獨立的注入代碼。
long _write(long fd, char *buf, unsigned long len)
{
long ret;
asm volatile (
"mov %0, %%rdi\n"
"mov %1, %%rsi\n"
"mov %2, %%rdx\n"
"mov $1, %%rax\n"
"syscall"
:
:"g"(fd), "g"(buf), "g"(len)
);
asm("mov %%rax, %0":"=r"(ret));
return ret;
}
void _exit(long status)
{
asm(
"mov $60, %%rax\n"
"syscall"
:
:"r"(status)
);
}
_start()
{
_write(1, "I am HotIce0\n", sizeof("I am HotIce0\n"));
_exit(0);
}
- 其中用到的%0 , %1這樣的數字,是用來引用,輸入參數和輸出參數。
編號的方式是,%0是第一個輸出參數,%n是最後一個輸入參數。 - 其中的$60,是立即數,也就是60。十六進制需要使用0x10這樣的寫法。
- 能操作的寄存器包括以下寄存器。
寄存器操作數約束:r (register operand constraint):gcc可以將變量保存在任何可用的GPR中g
GPR寄存器表 (通用目標寄存器)
±–±-------------------+
| r | Register(s) |
±–±-------------------+
| a | %eax, %ax, %al |
| b | %ebx, %bx, %bl |
| c | %ecx, %cx, %cl |
| d | %edx, %dx, %dl |
| S | %esi, %si |
| D | %edi, %di |
- 其中的
"g"(fd)
這種叫約束。
這樣的約束有很多種。比如以下常用的約束。
=
代表輸出變量用作輸出,原來的值會被新值替換。+
代表即可用作輸入,也可用作輸出。- “m” : A memory operand is allowed, with any kind of address that the machine supports in general.允許內存操作通過使用任何機器支持的地址類型。
- “o” : A memory operand is allowed, but only if the address is offsettable. ie, adding a small offset to the address gives a valid address.允許使用內存操作數,但前提是該地址是可偏移的。 即,向地址添加一個小偏移量會給出一個有效的地址。
- “V” : A memory operand that is not offsettable. In other words, anything that would fit the
m’ constraint but not the
o’constraint.不可偏移的內存操作,就是,任何的操作都適合用m修飾,但是不一定適用於o約束。 - “i” : An immediate integer operand (one with constant value) is allowed. This includes symbolic constants whose values will be known only at assembly time.立即數操作
- “n” : An immediate integer operand with a known numeric value is allowed. Many systems cannot support assembly-time constants for operands less than a word wide. Constraints for these operands should use ’n’ rather than ’i’.一個立即數操作使用一個已知的數值是被允許的,很多系統不支持爲操作少於一個字大小的對象彙編時構建。這個時候,應該使用n而不是i。
- “g” : Any register, memory or immediate integer operand is allowed, except for registers that are not general registers.任何寄存器,內存或者立即數操作都是被允許的,但是,寄存器必須是通用寄存器。
更多詳細的內容,可以參考官方文檔:http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html#s6