如何在没有EXE或ELF等容器的情况下手动编写和执行PURE机器代码?

com*_*ler 49 machine-code

我只需要一个hello world演示来查看机器代码实际上是如何工作的.

虽然windows的EXElinux'ELF接近机器代码,但它不是PURE

如何编写/执行PURE机器代码?

gel*_*sie 23

每个人都知道我们通常编写的应用程序是在操作系统上运行的.由它管理.

这意味着操作系统在机器上运行.所以我认为这就是你所说的PURE机器码.

因此,您需要研究操作系统的工作原理.

这是一些引导扇区的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
Run Code Online (Sandbox Code Playgroud)

您可以在这里找到更多资源:http://wiki.osdev.org/Main_Page.

结束.

如果你已经安装了nasm并且有软盘,你可以

nasm boot.asm -f bin -o boot.bin
dd if=boot.bin of=/dev/fd0
Run Code Online (Sandbox Code Playgroud)

然后,您可以从此软盘启动,您将看到该消息.(注意:您应该首先启动计算机软盘.)

事实上,我建议你在完整的虚拟机中运行该代码,例如:bochs,virtualbox等.因为很难找到带软盘的机器.

因此,步骤是首先,您应该需要安装完整的虚拟机.其次,通过推荐创建一个可视软盘:bximage第三,将bin文件写入该可视软盘.最后,从该可视软盘启动您的可视机器.

注意:在https://wiki.osdev.org中,有一些关于该主题的基本信息.

  • 程序集不是"纯粹的"机器代码,它是机器代码的抽象. (10认同)
  • "满容易"?那家伙给了你16行汇编程序和一个运行它的命令.从头开始编写自己的操作系统并不容易.我建议去虚拟机路由而不是软盘.首先,软盘驱动器很难实现.另一方面,在真机上启动自己的内核可能会损坏机器,但它不会损坏模拟器.最后,无需一直重启机器,测试起来要容易得多. (6认同)

Xlo*_*icX 23

可以手动编写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
Run Code Online (Sandbox Code Playgroud)

WIN/MZ/PE:

shellcode2exe.py(采用asciihex shellcode并创建一个合法的MZ PE exe文件)脚本位置:

http://zeltser.com/reverse-malware/shellcode2exe.py.txt

依赖性:

corelabs.coresecurity.com/index.php?module=Wiki&action=attachment&type=tool&page=InlineEgg&file=InlineEgg-1.08.tar.gz

提取

python setup.py build




sudo python setup.py install
Run Code Online (Sandbox Code Playgroud)

  • 你在哪里了解到这一点?你有一些可以分享的资源,我对它很感兴趣:-) (3认同)

Gre*_*ill 15

听起来你正在寻找旧的16位DOS .COM文件格式..COM文件的字节在程序段中偏移100h处加载(将它们限制为最大大小为64k - 256字节),并且CPU仅在偏移100h处开始执行.没有标题或任何类型的任何必需信息,只是原始CPU指令.

  • 当然,这是一个例子:http://99-bottles-of-beer.net/language-assembler-(intel-8086)-45.html (3认同)
  • 格雷格,这个例子只是更多的汇编代码,而不是纯粹的机器代码,啤酒是粗略的 (2认同)

D.S*_*nap 13

真实机器代码

运行测试需要什么:Linux x86 或 x64(在我的情况下,我使用的是 Ubuntu x64)

开始吧

此程序集 (x86) 将值 666 移动到 eax 寄存器中:

movl $666, %eax
ret
Run Code Online (Sandbox Code Playgroud)

让我们对其进行二进制表示:

二进制的操作码movl(movl 是一个操作数大小为 32 的 mov)是 = 1011

二进制指令宽度= 1

二进制寄存器eax = 000

有符号的 32 位二进制数666 = 00000000 00000000 00000010 10011010

666转换为小端是 = 10011010 00000010 00000000 00000000

二进制指令ret(返回)是 = 11000011

所以最终我们的纯二进制指令将如下所示:

1011(movl)1(width)000(eax)10011010000000100000000000000000(666) 11000011(ret)

把它们放在一起:

1011100010011010000000100000000000000000
11000011
Run Code Online (Sandbox Code Playgroud)

为了执行它,二进制代码必须放在具有执行权限的内存页面中,我们可以使用以下 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;
}
Run Code Online (Sandbox Code Playgroud)

来源:https : //www.hanshq.net/files/ones-and-zeros_42.c

我们可以使用以下方法编译它:

gcc source.c -o binaryexec

要执行它:

./binaryexec

然后我们通过第一组指令:

1011100010011010000000100000000000000000

按回车

并传递返回指令:

11000011

按回车

最后 ctrl+d 结束程序并得到输出:

函数返回 666

  • 你从哪里得到 MOV 等的操作码?另外为什么需要机器语言中的宽度命令? (3认同)

dat*_*olf 9

操作系统没有运行指令,CPU会这样做(除非我们谈论虚拟机操作系统,确实存在,我正在考虑Forth或类似的事情).然而,操作系统确实需要一些元信息才能知道,文件确实包含可执行代码,以及它希望环境看起来如何.ELF不仅仅靠近机器代码.这机器代码,以及操作系统的一些信息,知道它应该让CPU实际执行那个东西.

如果你想要比ELF更简单的东西,但是*nix,看看a.out格式,这要简单得多.传统上,如果没有指定输出名称,*nix C编译器会(仍)将其可执行文件写入名为a.out的文件中.


Pat*_*ick 1

在 Windows(至少 32 位 Windows)上,您可以使用 .com 文件执行 RAW 指令。

例如,如果您将此字符串保存在记事本中,扩展名为 .com:

X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*
Run Code Online (Sandbox Code Playgroud)

它将打印一个字符串并启动您的防病毒软件。

  • 当作为 com 文件运行时,它都是有效的 X86。 (8认同)
  • 常见的误解是 EICAR 只是一个字符串。Patrick 是完全正确的,该程序使用 int 21 来打印以 $ 结尾的字符串“EICAR-STANDARD-ANTIVIRUS-TEST-FILE。但是由于此完整中断不是 ASCII 可打印的,因此导致该字符串的代码是自我修改的,以便可以使用 INT 21。阅读以下链接以获取引人入胜的完整分步分析:http://thestarman.pcministry.com/asm/eicar/eicarcom.html (7认同)