pop↑ push↓

☆ (ゝω・)v

VS2019でLinuxメモ 2

前回) popush.hatenablog.com 今回)asmの埋め込み、so-hijack実験

準備

Ubuntuにnasmをインストールする。

$ sudo apt-get install nasm

cmakeでnasmを使う

gccはx64になってもインラインアセンブラが使える*1。インラインアセンブラでやるときは完全に空の関数を作りたくなるが、x64でそれも可能*2

しかし記述が冗長になるのと、レジスタを%で指定するのが好みに合わないのでnasm*3を使えるようにしたい。

nasmをCMakeで使うには自分で環境変数を設定しないとならない*4。下記のような記述をCmakeList.txtに追加する。ldではなくgccを使うように解説している資料もあるが基本的には同じ。自分でリンク設定を追加してあげないといけない。

set(CMAKE_ASM_NASM_LINK_EXECUTABLE "ld <CMAKE_ASM_NASM_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES>")
set(CMAKE_ASM_NASM_OBJECT_FORMAT "elf64")

project(sample1 CXX ASM_NASM)

add_executable (a "hoge_asm.asm" "sample1.cpp" "sample1.h")

if(CMAKE_BUILD_TYPE STREQUAL "Debug")
    target_compile_options(a PRIVATE -g -Fdwarf)
endif()

asmの記述はこんな感じ。GLOBAL をつけると関数を公開でき、cpp側から参照できるようになる。

SECTION .text

GLOBAL geso       ; the standard gcc entry point

geso:
    push    rbp;     ; set up stack frame, must be aligned
    nop;
    nop;    
    pop     rbp;
    mov     rax,5;
    ret;

cpp側のコードはこんな感じ。上で作ったgeso関数を呼び出している。externは必要ないかもしれないが念のため。理由はDLLの説明を参照。

#include "sample1.h"

using namespace std;

extern "C" {
    int geso();
}

int main()
{
    int result = geso();

    cout << "asm return : " << result << endl;

    return 0;
}

ブレークポイントを置いて、これを実行すると逆アセンブリコードも見れるし、レジスタもみれる。

f:id:saito-matanki:20200524121248p:plain

so-hijackのコードをデバッグする

こちらは提供されたso-hijackのコード。

github.com

どうやら__attribute__((constructor))とLD_PRELOADを使うハックがLinuxにはある模様*5

対象のプログラムの実行前にLD_PRELOADを設定しておけば、その設定されたsoファイルが追加で読み込まれるらしい。これはdllのinjectionと似ている。またそのままだとプログラムの実行後に追加で読み込まれたsoが実行されてしまうため、__attribute__((constructor))をつけて対象のプログラムのmain()よりも先に実行させるらしい。正直なぜこんな仕組みが存在しているかわからない。

読み込まれたso-hijackがパターンの検索、置き換えを実行しているのは次回に見るとして、まずこれをvs2019でデバッグ可能にする。

まずコードをコピーしてくる。

f:id:saito-matanki:20200524122450p:plain

次にアタッチ設定だが、ここ*6に書いてあるのだがわかりにくい。以下のようにターゲットを選択した状態でメニューから実行する

f:id:saito-matanki:20200524123041p:plain

この結果、Launch.vs.jsonには下記のような記述が追加される。しかしこのファイルはgitで管理されたりしないので、別のマシンではその都度設定する必要がある。重要なのはprojectとprojectTargetがcmakeの設定を指しているかでこれが正しくないとビルドできない。

f:id:saito-matanki:20200524123322p:plain

次にLD_PRELOADのgdbの確認方法だが、環境変数に設定すればよい*7。なので、Launch.vs.jsonのenvに下記のように追加する。

f:id:saito-matanki:20200524123645p:plain

後はターゲットを実行すると変更が入っているのが確認できる。

f:id:saito-matanki:20200524123807p:plain