é£ã³å ¥ãã§ããRubyã¢ããã³ãã«ã¬ã³ãã¼ãã®2 17æ¥ç®ã®è¨äºã§ããæ¨æ¥ã¯ãªãã¨ãªãä¼¼ããããªï¼ï¼ï¼ã Rubyã®8鲿°ã¨2鲿°ã®æ§æã¨ã©ã¼æã®éã ã®è©±ã§ãã
仿¥ã¯Rubyã§æ§é ä½ãã¨è¨ããããã¤ããªããã¯ãããæ§é ä½ãæ±ã話ã®è§¦ãããã¾ããclass Structã®è©±ã¯ããªãã
ãã¦ã¿ãªãã㯠String#unpack/Array#pack
ã使ã£ã¦ã¾ããï¼
ãããæ£ç´ãªè©±ãããã¨ãããããå¤ãã®æ¹ã¯ä½¿ã£ã¦ããªãã¦ã使ã£ã¦ããæ¹ã大åã¯base64æååãçæãã m
ãã©ã¼ãããããããã使ã£ã¦ããªãã®ã§ã¯ãªããã¨æ¨æ¸¬ãã¦ãã¾ãã
["Hello World"].pack('m') #=> "SGVsbG8gV29ybGQ=\n"
ã¼ããä»ã¾ã§ã¯ããã ã£ãã®ã§ãããæè¿ã¯ä»ã®ãã©ã¼ããããæ¥ã«ä½¿ãããã«ãªãã¾ãããã¨ããã®ããCã§æ±ãæ§é ä½ãå®è³ªãã¤ããªåãç°¡åã«Rubyã®ä¸çã«æã£ã¦ããéã«ä¾¿å©ãªä»£ç©ã ããã§ããå»å¹´ã®çµãããããã£ã¨ ffiãã¬ãããªä½¿ã£ãgem ã®éçºã«å¤ããã§ããã®ã§ããã詳ãããªã£ã¦ãã¾ã£ãã
ã¨ãããã¨ã§ä»æ¥ã¯æ§é ä½ã¨ffiã¨pack/unpackã®è©±ããã¦ããã¾ãã
ä»åã®ç°å¢
Cã®æ§é ä½ãRubyã§åãåºãã
Cã®æ§é ä½ã¯ã©ãè¨ãå ´åã«åºããããã¨ããã¨ã主ã«ãffiã§Cã®é¢æ°ãæ±ãããå ´åãè¤éãªé¢æ°ãå¼ã³ãããªã£ããå¿ è¦ã«ãªãã¾ãã
Rubyã®æ¨æºæ·»ä»ï¼2.7段éã§ã¯ï¼ã®gemã§ããfiddleã使ãã¾ããã©ã¤ãã©ãªã³ã¼ã«ã¨ãã¦ã® uname(2)
ãRubyã¹ã¯ãªããããå¼ãã§ã¿ã¾ãããã
ã¾ãlibcã®ãã³ãã«ãåãã¾ãã
require 'fiddle' libc = Fiddle::Handle.new('libc.so.6')
libcã® uname
ã®ã¢ãã¬ã¹ãã颿°ãåãåºãã¾ããå®ç¾©ã¯ man 2 uname
ã®éãã§ããã void*
ãåãåã£ã¦ int
ãè¿ã颿°ã¨ãã¾ãã
uname = Fiddle::Function.new(libc.sym('uname'), [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
ãã¦ã弿°ã® struct utsname *buf
ç¸å½ã®ãã¤ã³ã¿ã表ç¾ããFiddle::Pointerã®ã¤ã³ã¹ã¿ã³ã¹ãä½ãã¾ããããµã¤ãºã¯ã ã«ã¼ãã«ã®ã³ã¼ã ãªã©ãçºãã¦å¤å char[65]
ã®ã¡ã³ãã6ã¤ããã¨èãã¦ãã®ãµã¤ãºã確ä¿ãã¾ãã
uts = Fiddle::Pointer.malloc(65 * 6)
ããã弿°ã«å¼ã³åºãã
uname.call(uts)
#=> 0
uts
ã«ã¯å¤ãåã¾ã£ã¦ãã¾ãã uts.to_str
ã§ç¢ºèªã§ãã¾ãããªã to_s
ã ã¨æåã® \0
ã«çªãå½ãã£ãã¨ããã¾ã§ããåºãã¦ããã¾ããã
uts.to_str => "Linux\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00ubuntu2004.localdomain\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x005.8.0-29-generic\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00#31~20.04.1-Ubuntu SMP Fri Nov 6 16:10:42 UTC 2020\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00x86_64\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00(none)\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00"
ãããRubyã§æ±ãããããã¾ãããã以ä¸ã®ããã«ãã©ã¼ããããæå®ãããchar[65]
ã®ã¡ã³ãã6ã¤ããæ§é ä½ãã¨ãã¦unpackãã¾ãã
pp uts.to_str.unpack("Z65 Z65 Z65 Z65 Z65 Z65") ["Linux", "ubuntu2004.localdomain", "5.8.0-29-generic", "#31~20.04.1-Ubuntu SMP Fri Nov 6 16:10:42 UTC 2020", "x86_64", "(none)"]
ã¯ãOKããã
ä»ãä¾ãã° clock_gettime(2)
ãªããã§ãå¤ãåãã¾ããããç§ã¾ã§åãã¾ããã
require 'fiddle' libc = Fiddle::Handle.new('libc.so.6') f = Fiddle::Function.new( libc.sym('clock_gettime'), [Fiddle::TYPE_INT, Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT ) p = Fiddle::Pointer.malloc(16) f.call(Process::CLOCK_REALTIME, p) p.to_str.unpack("l! l!") #=> [1608116263, 831128860]
ç¡è«ãéã«æ§é ä½ã表ç¾ããæååã«ããã¯ãããã¨ãå¯è½ã§ããã¨ã¯ããããã®è¾ºãã®ã·ã¹ãã ã³ã¼ã«å¼ã³åºãã¯ãæ®éRubyã®æ¨æºã©ã¤ãã©ãªãªã©ãæä¾ããã¯ã©ã¹ã»ã¡ã½ããã使ãã¨ã¯æãã¾ãã*1...ã
ãã ãããã¾ã®èª¬æã«ãããéããä¾ãã°IO#ioctl
ãªã©ã®ã¡ã½ããã®å¼æ°ã«ã¯ããã¯ãããæ§é ä½ã渡ãæãããã®ã§ãããè¨ãå ´åã«ã¯èªåã§ãã¤ããªåãç¨æãããã¨ã«ãªãã¾ããioctl(2)
ãªããç´æ¥å¼ã°ãã¼ããã¨è¨ãæè¦ã«ã¯ããããã ããã¨ãè¿äºãã¾ãã
ãã¨ã Fiddle::Importer#struct
ã®ãããªããå°ãé«ã¬ãã«ãªAPIã使ãã¨æèããªãã¦ãæ¸ãããã«ã¯ãªã£ã¦ãã¾ãã...ã
ELFãã¤ããªãæ§é ä½ã«unpackãã
ããå°ãå®ç¨çï¼ï¼ï¼ãªä¾ã¨ãã¦ã¯ELFã®æ å ±ã®ãã¼ãºãããã¾ãã
ããããå
ã®è¨äºã¯ä»¥ä¸ã® man 5 elf
ã¨ç¨ãã£ãããªããèªãã¨ããã§ãããã¨ããæå
ã« elf.h
ãªã©ãç¨æãã¦ãã ãããLinuxã®ã½ã¼ã¹ã³ã¼ãã® ãã ã ãã ãéãã¨ãã¾ãããã
ããã«ããã¨ãELFãããã®æ§é ä½ã¯ä»¥ä¸ã®ããã«ãªãã¾ãã䏿¦ã64bitã¢ã¼ããã¯ãã£ã«æ±ºãæã¡ãã¾ãã
#define EI_NIDENT 16 typedef struct { unsigned char e_ident[EI_NIDENT]; uint16_t e_type; uint16_t e_machine; uint32_t e_version; Elf64_Addr e_entry; Elf64_Off e_phoff; Elf64_Off e_shoff; uint32_t e_flags; uint16_t e_ehsize; uint16_t e_phentsize; uint16_t e_phnum; uint16_t e_shentsize; uint16_t e_shnum; uint16_t e_shstrndx; } Elf64_Ehdr;
Elf64_*
ã¯ä»¥ä¸ã®ãããªå®ç¾©ã§ãã
typedef __u64 Elf64_Addr; typedef __u16 Elf64_Half; typedef __s16 Elf64_SHalf; typedef __u64 Elf64_Off; typedef __s32 Elf64_Sword; typedef __u32 Elf64_Word; typedef __u64 Elf64_Xword; typedef __s64 Elf64_Sxword;
ãã®è¾ºã®æ å ±ãåèã«packãã©ã¼ãããæååãä½ãã¨ä»¥ä¸ã®ããã«ãªãã¨æããã¾ãã
"Z16 S! S! I! L! L! L! I! S! S! S! S! S! S!"
ãã¦ãããããELFå½¢å¼ã®ãã¤ããªã®å é ã¯ãã®æ§é ä½ã«unpackã§ããããã«ãªã£ã¦ãã¾ããbashã§è©¦ãã¦ã¿ã¾ãããã
b = File.read("/bin/bash") b.unpack "Z16 S! S! I! L! L! L! I! S! S! S! S! S! S!" => ["\x7FELF\x02\x01\x01", 3, 62, 1, 197680, 64, 1181528, 0, 64, 56, 13, 64, 30, 29]
ããã§:
- 2çªç®
e_type = 3
ã¯ET_DYN
ã«å¯¾å¿ - 3çªç®
e_machine = 62
ã¯EM_X86_64
ã«å¯¾å¿ - 4çªç®
e_version = 1
ã¯EV_CURRENT
ã«å¯¾å¿ - 5çªç®
e_entry
ã¯ã"0x%x" % 197680
=>"0x30430"
ã§ãã readelf
ã®çµæã§çãåãããã¾ããããã©ãã§ããï¼ ã¡ããã¨ãã¼ãºã§ãã¦ãããã§ãã
$ readelf -h /bin/bash ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: DYN (Shared object file) Machine: Advanced Micro Devices X86-64 Version: 0x1 Entry point address: 0x30430 Start of program headers: 64 (bytes into file) Start of section headers: 1181528 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 13 Size of section headers: 64 (bytes) Number of section headers: 30 Section header string table index: 29
ããã°ã©ã ããããunpackãã
ããã«ãããã°ã©ã ãããã¼ã«ãæ½ã£ã¦ã¿ã¾ããä¸è¨ã®çµæã®éã e_phoff = 64
ã e_phnum = 13
ã§ããbashã®ããã°ã©ã ã®ãã¤ããªã®ã65ãã¤ãç®ãã13åã®ELFããã°ã©ã ããããããããã§ãã
ELFããã°ã©ã ãããæ§é ä½ã¯ãmanã«ããã¨ä»¥ä¸ã
typedef struct { uint32_t p_type; uint32_t p_flags; Elf64_Off p_offset; Elf64_Addr p_vaddr; Elf64_Addr p_paddr; uint64_t p_filesz; uint64_t p_memsz; uint64_t p_align; } Elf64_Phdr;
packãã©ã¼ãããã§ã¯ "I! I! L! L! L! L! L! L!"
ã§ãããµã¤ãºã¯ e_phentsize
ã®ã¯ãã§ãããã¤ãã§ã«Rubyä¸ã§ç¢ºèªãã¦ããã¾ãããã
[0,0,0,0,0,0,0,0].pack("I! I! L! L! L! L! L! L!").size #=> 56
ã§ã¯bashã®ããã°ã©ã ããããèªã¿åãã¾ããæåã¯ããããæãã
f = File.open("/bin/bash") f.seek 64 b = f.read(56) b.unpack("I! I! L! L! L! L! L! L!") => [6, 4, 64, 64, 64, 728, 728, 8]
2ã¤ç®ã¯ãããã«56ãã¤ãèªã¿åããããã°OKã§ããã
f.read(56) .unpack("I! I! L! L! L! L! L! L!") => [3, 4, 792, 792, 792, 28, 28, 1]
ãã£ãã1çªç® p_type
ã¨2çªç® p_flags
ã®å¤ã«æ³¨ç®ãã¾ããåããã宿°ã¯ãããªæãã®ããã§ãã
#define PT_NULL 0 #define PT_LOAD 1 #define PT_DYNAMIC 2 #define PT_INTERP 3 #define PT_NOTE 4 #define PT_SHLIB 5 #define PT_PHDR 6 #define PT_TLS 7 /* Thread local storage segment */ // ã¤ã«ç¶ã //... #define PF_R 0x4 #define PF_W 0x2 #define PF_X 0x1
1è¦ç´ ç®ã¯ãPT_PHDR, PF_R, ...ãã2è¦ç´ ç®ã¯ãPT_INTERP, PF_R, ...ãã¨æããã¾ããçãåããã¯ãã£ã±ã readelf
ã§...ã
$ readelf -l /bin/bash Elf file type is DYN (Shared object file) Entry point 0x30430 There are 13 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040 0x00000000000002d8 0x00000000000002d8 R 0x8 INTERP 0x0000000000000318 0x0000000000000318 0x0000000000000318 0x000000000000001c 0x000000000000001c R 0x1 [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x000000000002ce70 0x000000000002ce70 R 0x1000 LOAD 0x000000000002d000 0x000000000002d000 0x000000000002d000 0x00000000000b0705 0x00000000000b0705 R E 0x1000 LOAD 0x00000000000de000 0x00000000000de000 0x00000000000de000 0x0000000000036198 0x0000000000036198 R 0x1000 ...
æåãã1ã¤ç®ã2ã¤ç®ãã¡ããã¨å¯¾å¿ããå¤ã«ãªã£ã¦ããã¨å¤æã§ãã¾ãã
çµè«
- Rubyã®
String#unpack/Array#pack
ãç¨ããæ§é ä½ã表ç¾ãããã¤ããªãpack/unpackã§ããã - ELFãããã¯æ§é ä½ã«unpackããã°ãã¼ãºã§ããã
- Rubyã§ãã¤ããªè§£æããã¨ä¾¿å©ã
ãã£ã¨ã«ããæçµèª²é¡ã§readelf
ã³ãã³ãèªä½ã¯ã©ãã§ããã
Rubyã®packã«ã¤ãã¦ãå°ãã§ãè¬ãè§£ããã°å¹¸çã§ãã
åèã«ãªããµã¤ã
åããããªãã¨ãGoã§è¡ã£ãä¾ã§ããRubyãã¾ããªããï¼ï¼ï¼
ã¨ãããã¨ã§Rubyã¢ãã«ã¬ã®ãã®2ãææ¥ãæ¸ãæåéä¸ã®æ¨¡æ§ã