我只需要一个 hello world 演示来看看机器代码是如何工作的。
虽然 windows 的EXE和 linux 的ELF接近机器码,但不是PURE
如何编写/执行PURE机器代码?
我只需要一个 hello world 演示来看看机器代码是如何工作的。
虽然 windows 的EXE和 linux 的ELF接近机器码,但不是PURE
如何编写/执行PURE机器代码?
您可以手动编写纯机器代码而无需组装
Linux/ELF:https ://github.com/XlogicX/m2elf 。这仍然是一项正在进行的工作,我昨天才开始工作。
“Hello World”的源文件如下所示:
b8 21 0a 00 00 #moving "!\n" into eax
a3 0c 10 00 06 #moving eax into first memory location
b8 6f 72 6c 64 #moving "orld" into eax
a3 08 10 00 06 #moving eax into next memory location
b8 6f 2c 20 57 #moving "o, W" into eax
a3 04 10 00 06 #moving eax into next memory location
b8 48 65 6c 6c #moving "Hell" into eax
a3 00 10 00 06 #moving eax into next memory location
b9 00 10 00 06 #moving pointer to start of memory location into ecx
ba 10 00 00 00 #moving string size into edx
bb 01 00 00 00 #moving "stdout" number to ebx
b8 04 00 00 00 #moving "print out" syscall number to eax
cd 80 #calling the linux kernel to execute our print to stdout
b8 01 00 00 00 #moving "sys_exit" call number to eax
cd 80 #executing it via linux sys_call
赢/MZ/PE:
shellcode2exe.py(采用 asciihex shellcode 并创建一个合法的 MZ PE exe 文件)脚本位置:
http://zeltser.com/reverse-malware/shellcode2exe.py.txt
依赖:
提炼
python setup.py build
sudo python setup.py install
大家都知道,我们平时写的应用程序是运行在操作系统上的。并由它管理。
这意味着操作系统在机器上运行。所以我认为那是你所说的纯机器代码。
因此,您需要研究操作系统的工作原理。
这是一些用于引导扇区的 NASM 汇编代码,可以在 PURE 中打印“Hello world”。
org
xor ax, ax
mov ds, ax
mov si, msg
boot_loop:lodsb
or al, al
jz go_flag
mov ah, 0x0E
int 0x10
jmp boot_loop
go_flag:
jmp go_flag
msg db 'hello world', 13, 10, 0
times 510-($-$$) db 0
db 0x55
db 0xAA
您可以在此处找到更多资源:http ://wiki.osdev.org/Main_Page 。
结尾。
如果你已经安装了 nasm 并且有一张软盘,你可以
nasm boot.asm -f bin -o boot.bin
dd if=boot.bin of=/dev/fd0
然后,您可以从该软盘启动,您将看到该消息。(注意:您应该将计算机的第一次引导设为软盘。)
实际上,我建议您在完整的虚拟机中运行该代码,例如:bochs、virtualbox 等。因为很难找到带有软盘的机器。
所以,步骤是首先,你应该需要安装一个完整的虚拟机。其次,通过命令创建一个可视软盘:bximage 第三,将bin文件写入该可视软盘。最后,从那张可视软盘启动您的可视机器。
注意:在https://wiki.osdev.org中,有一些关于该主题的基本信息。
听起来您正在寻找旧的16 位 DOS.COM
文件格式。文件的字节.COM
在程序段的偏移量 100h 处加载(限制它们的最大大小为 64k - 256 字节),CPU 只是在偏移量 100h 处开始执行。没有标题或任何类型的任何必需信息,只有原始 CPU 指令。
运行测试需要什么:Linux x86 或 x64(在我的情况下,我使用的是 Ubuntu x64)
开始吧
这个程序集(x86)将值 666 移动到 eax 寄存器中:
movl $666, %eax
ret
让我们对其进行二进制表示:
二进制操作码movl(movl 是操作数大小为 32 的 mov)= 1011
二进制指令宽度= 1
二进制寄存器eax = 000
带符号的 32 位二进制数666为 = 00000000 00000000 00000010 10011010
666转换为小端是= 10011010 00000010 00000000 00000000
二进制指令ret (return) = 11000011
所以最终我们的纯二进制指令将如下所示:
1011(movl)1(width)000(eax)10011010000000100000000000000000(666)
11000011(ret)
把它们放在一起:
1011100010011010000000100000000000000000
11000011
为了执行它,二进制代码必须放在具有执行权限的内存页中,我们可以使用以下 C 代码来做到这一点:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
/* Allocate size bytes of executable memory. */
unsigned char *alloc_exec_mem(size_t size)
{
void *ptr;
ptr = mmap(0, size, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANON, -1, 0);
if (ptr == MAP_FAILED) {
perror("mmap");
exit(1);
}
return ptr;
}
/* Read up to buffer_size bytes, encoded as 1's and 0's, into buffer. */
void read_ones_and_zeros(unsigned char *buffer, size_t buffer_size)
{
unsigned char byte = 0;
int bit_index = 0;
int c;
while ((c = getchar()) != EOF) {
if (isspace(c)) {
continue;
} else if (c != '0' && c != '1') {
fprintf(stderr, "error: expected 1 or 0!\n");
exit(1);
}
byte = (byte << 1) | (c == '1');
bit_index++;
if (bit_index == 8) {
if (buffer_size == 0) {
fprintf(stderr, "error: buffer full!\n");
exit(1);
}
*buffer++ = byte;
--buffer_size;
byte = 0;
bit_index = 0;
}
}
if (bit_index != 0) {
fprintf(stderr, "error: left-over bits!\n");
exit(1);
}
}
int main()
{
typedef int (*func_ptr_t)(void);
func_ptr_t func;
unsigned char *mem;
int x;
mem = alloc_exec_mem(1024);
func = (func_ptr_t) mem;
read_ones_and_zeros(mem, 1024);
x = (*func)();
printf("function returned %d\n", x);
return 0;
}
来源:https ://www.hanshq.net/files/ones-and-zeros_42.c
我们可以使用以下方法编译它:
gcc source.c -o binaryexec
要执行它:
./binaryexec
然后我们传递第一组指令:
1011100010011010000000100000000000000000
按回车
并通过返回指令:
11000011
按回车
最后 ctrl+d 结束程序并得到输出:
函数返回 666
操作系统没有运行指令,CPU 运行(除非我们谈论的是确实存在的虚拟机操作系统,我正在考虑 Forth 或类似的东西)。然而,操作系统确实需要一些元信息才能知道,文件实际上包含可执行代码,以及它期望其环境看起来如何。ELF 不只是接近机器代码。它是机器代码,以及一些信息,让操作系统知道它应该让 CPU 实际执行该操作。
如果您想要比 ELF 更简单但 *nix 的东西,请查看 a.out 格式,它要简单得多。如果没有指定输出名称,传统上 *nix C 编译器会(仍然)将其可执行文件写入名为 a.out 的文件中。
使用纯机器代码,您可以使用任何能够编写文件的语言。甚至 Visual basic.net 也可以写入 8、16、32、64 位,同时在写入时在 int 类型之间进行交换。
您甚至可以设置让 vb 根据需要在循环中写出机器代码,例如 setpixel,其中 x,y 发生变化,并且您拥有 argb 颜色。
或者,定期在 Windows 中创建您的 vb.net 程序,并用于NGEN.exe
制作程序的本机代码文件。它一次性创建特定于 ia-32 的纯机器代码,将 JIT 调试器放在一边。
当以嵌入式系统为目标时,您可以制作 rom 或 ram 的二进制映像,严格来说是程序中的指令和相关数据。并且通常可以将该二进制文件写入闪存/ROM并运行它。
操作系统想要知道的远不止这些,开发人员通常希望在他们的文件中留下更多的东西,以便他们以后可以调试或做其他事情(用一些可识别的符号名称反汇编)。此外,嵌入式或在操作系统上,您可能需要将 .text 与 .data 与 .bss 与 .rodata 等分开,而 .elf 等文件格式为此提供了一种机制,首选用例是加载该 elf 一些某种加载程序,无论是操作系统还是对微控制器的 rom 和 ram 进行编程的东西。
.exe 也有一些标题信息。如前所述,.com 没有加载到地址 0x100h 并在那里分支。
要从可执行文件创建原始二进制文件,例如使用 gcc 创建的 elf 文件,您可以执行类似的操作
objcopy file.elf -O 二进制文件.bin
如果程序是分段的(.text、.data 等)并且这些段不是背靠背的,那么二进制文件可能会变得非常大。再次以嵌入式为例,如果 rom 位于 0x00000000 并且数据或 bss 位于 0x20000000 即使您的程序只有 4 个字节的数据,objcopy 也会创建一个 0x20000004 字节的文件来填充 .text 和 .data 之间的间隙(因为它应该因为那是你要求它做的)。
你想做什么?读取 elf 或 intel hex 或 srec 文件非常简单,从中您可以看到二进制文件的所有位和字节。或者拆卸精灵或任何东西也会以人类可读的形式向你展示。(objdump -D file.elf > file.list)
这是很好的回应,但为什么有人想要这样做可能会更好地指导答案。我认为最重要的原因是完全控制他们的机器,尤其是缓存写入,以获得最佳性能,并防止任何操作系统共享处理器或虚拟化您的代码(从而减慢它的速度),尤其是在这些日子里窥探你的代码也是如此。据我所知,assembler 不处理这些问题,M$/Intel 和其他公司将此视为侵权或“针对黑客”。然而,这是非常错误的。如果您的汇编代码被移交给操作系统或专有硬件,那么真正的优化(可能在 GHz 频率下)将是遥不可及的。这是一个非常重要的科学技术问题,因为如果没有硬件优化,我们的计算机就无法充分发挥其潜力,并且通常计算低于它的几个数量级。可能有一些解决方法或一些开源硬件可以实现这一点,但我还没有找到它。一分钱任何人的想法。
下一个程序是我用Machine Code 16 bit(intel 8086)写的一个Hello World程序,如果你想了解机器码,我建议你先学习Assembly,因为Assembly中的每一行代码都转换为A code line in机器码。好吧,我知道我来自世界上为数不多的仍然使用机器代码而不是汇编编程的人。
顺便说一句,要运行它,请使用“.com”扩展名保存文件并在 DOSBOX 上运行!
在 Windows(至少 32 位 Windows)上,您可以使用 .com 文件执行 RAW INSTRUCTIONS。
例如,如果您将此字符串保存在带有 .com 扩展名的记事本中:
X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*
它将打印一个字符串并启动您的防病毒软件。