代码如下:
SECTION .bss
BUFFLEN equ 16 ; 我们一次从这个文本读取16个字节
Buff resb BUFFLEN ; 文本缓冲区本身
SECTION .data
HexStr: db " 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", 10
HEXLEN equ $-HexStr
Digits: db "0123456789ABCDEF"
SECTION .text
global _start
_start:
nop ; 这个无操作指令让gdb非常高兴
; 从标准输入中读取满满一缓冲区的文本
Read: mov eax, 3 ; 指定sys_read系统调用
mov ebx, 0 ; 指定文件描述符0:标准输入
mov ecx, Buff ; 传递即将从中读取数据的缓冲区的地址
mov edx, BUFFLEN ; 传递一次循环中要读入的字节数
int 80h ; 调用sys_read来填充缓冲区
mov ebp, eax ; 复制sys_read的返回值并妥善保管
cmp eax, 0 ; 如果“eax = 0”,则sys_read到了标准输入的结尾
je Done ; 如果(与0相比较)相等,则跳转
; 设置寄存器用于处理缓冲区步骤:
mov esi, Buff ; 将文本缓冲区的地址放入esi寄存器中
mov edi, HexStr ; 将线性字符串的地址放入edi寄存器中
xor ecx, ecx ; 将线性字符串指针清0
; 检查缓冲区,将二进制数值转换为16进制位元
Scan:
xor eax, eax ; 将寄存器eax清零
; 这里我们可以计算相对于HexStr的偏移地址,它等于ecx中的值乘以3
mov edx, ecx ; 将字符串计数器的值复制到edx中
shl edx, 1 ; 通过左移位操作将指针的值乘以2
add edx, ecx ; 完成乘以3操作
; 从缓冲区中获取一个字符,并将其同时存入eax和ebx中:
mov al, byte [esi+ecx] ; 从输入缓冲中取出一个字节,送入al
mov ebx, eax ; 为了求得第二个“半字节”,将该字节复制到bl中
; 查找低半字节符并将其插入字符串
and al, 0Fh ; 屏蔽除了低半字节之外的所有内容
mov al, byte [Digits+eax] ; 查找与该半字节相等的字符
mov byte [HexStr+edx+2], al ; 将最低有效位(LSB)字符位元(digit)写入线性字符串
; 查找高半字节符并将其插入字符串
shr bl, 4 ; 将字符的高四位移入低四位
mov bl, byte [Digits+ebx] ; 查找与该半字节相等的字符
mov byte [HexStr+edx+1], bl ; 将最高有效位(MSB)字符位元写入线性字符串
; 将缓冲区指针指向下一个字符,看一下任务是否完成
inc ecx ; 增加线性字符串指针的值
cmp ecx, ebp ; 与缓冲区中的字符数进行比较
jna Scan ; 如果ecx小于等于缓冲区中的字符数,转回去继续循环
; 将这行十六进制写到标准输出:
Write: mov eax, 4 ; 指定sys_write系统调用
mov ebx, 1 ; 指定文件描述符,1是标准输出
mov ecx, HexStr ; 传递线性字符串的偏移地址
mov edx, HEXLEN ; 传递线性字符串的大小
int 80h ; 调用sys_write
jmp Read ; 回去继续循环,加载另一满满的缓冲区数据
Done: mov eax, 1 ; 指定Exit系统调用
mov ebx, 0 ; 返回一个零代码
int 80h ; 进行系统调用来终止程序
使用方法:
./hexdump < inputfile > outputfile