Microsoft MVP성태의 닷넷 이야기
글쓴 사람
홈페이지
첨부 파일

머신 바이트 배열로부터 역어셈블해주는 라이브러리 - Udis86 Assembler

가끔, 기계어로 표현된 바이트 숫자값들로부터 어셈블리 니모닉(mnemonic) 형식을 보고 싶을 때가 있는데요. 이를 위해 인텔에서 제공해주는 문서를 읽고 직접 구현할 수도 있겠지만,

Intel® 64 and IA-32 Architectures Software Developer Manuals
; http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html

역시나 다른 분이 만들어 놓은 라이브러리가 더 좋아 보일 수 밖에 없습니다. ^^;

Visual Studio solution to build Netwide Assembler 
; https://github.com/agguro/Nasm-project-vs

비주얼 스튜디오 Team Explorer에서 "https://github.com/agguro/Nasm-project-vs.git" 경로를 clone하고, ".\2.12rc5\NasmProject.sln" 솔루션 파일을 열어 그냥 빌드해 주시면 됩니다.

"Netwide Assembler" 이외에, 라이브러리 형식으로 좀더 모듈화가 잘 되어 있는 것도 있습니다.

Udis86 Disassembler Library for x86 / x86-64
; http://udis86.sourceforge.net/
; https://github.com/vmt/udis86

그런데, 컴파일을 위해서는 사전 작업을 좀 해야 합니다. 우선, .\BuildVS2010\buildVS2010.bat 파일에서 자신이 가지고 있는 비주얼 스튜디오 버전에 맞게 경로를 수정해 줍니다. (저는 Visual Studio 2015에서 빌드할 것이므로 14.0으로 했습니다.)

echo off
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_amd64

msbuild.exe udis86.sln /t:Clean
msbuild.exe build.proj /t:Clean,BuildRelease_x86,BuildRelease_x64,PostBuild
REM msbuild.exe build.proj /t:Clean,BuildRelease_x86,BuildRelease_x64,BuildDebug_x86,BuildDebug_x64,PostBuild
pause

그 다음 Python 2.7이 설치되어 있어야 하는데, 경로가 반드시 c:\python27 이어야 합니다. (다른 곳에 설치했다면 약간의 조정이 필요합니다. 이에 대해서는 .\BuildVS2010\README.txt 파일을 참조하세요.)

Python 2.7 Release
; https://www.python.org/download/releases/2.7/

자, 이제 준비는 끝입니다. 명령행에서 다음과 같이 한번 실행해 줍니다.

.\BuildVS2010> buildVS2010.bat

정상적으로 빌드가 되었다면 이후 ".\BuildVS2010\udis86.sln" 솔루션 파일을 비주얼 스튜디오에서 열어 직접 빌드할 수 있습니다.

포함된 프로젝트는 "libudis86" 정적 라이브러리 유형과 "udcli" 콘솔 프로젝트 유형인데, udcli는 libudis86을 이용한 명령행 프로그램이므로 실제로 우리가 필요한 것은 libudis86입니다. 기본적으로는 정적 .lib를 생성하도록 되어 있는데, 빌드 Configuration을 Debug-DLL(또는 Release-DLL)로 바꾸면 윈도우 동적 .dll로도 만들 수 있습니다.

여기서는 C#에서 좀더 사용하기 쉽도록 libudis86 정적 라이브러리를 포함하는 Win32 DLL 프로젝트를 별도로 만들어 다음의 함수를 추가적으로 export 하겠습니다.

// http://stackoverflow.com/questions/10737644/convert-const-char-to-wstring
std::wstring s2ws(const std::string& str)
{
    int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
    std::wstring wstrTo(size_needed, 0);
    MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
    return wstrTo;
}

WINLIBUDIS86_API  const wchar_t * __stdcall GetDisassemble(int bitMode, __int64 baseAddress, BYTE *input, int inputLen)
{
    ud_t u;

    ud_init(&u);
    ud_set_input_buffer(&u, input, inputLen);
    
    ud_set_pc(&u, baseAddress);
    ud_set_mode(&u, bitMode);
    ud_set_syntax(&u, UD_SYN_INTEL);

    StringBuilder sb;

    while (ud_disassemble(&u))
    {
        sb.push_back(ud_insn_off(&u), 16);
        sb.push_back(' ');

        wstring txt = s2ws(ud_insn_hex(&u));
        sb.push_back(txt);
        sb.push_back(' ');

        txt = s2ws(ud_insn_asm(&u));
        sb.push_back(txt);

        sb.push_back('\n');
    }

    wstring result = sb.ToString();
    int chLen = result.size();

    int byteLen = (chLen + 1) * sizeof(wchar_t);

    wchar_t *pBuf = (wchar_t *)::CoTaskMemAlloc(byteLen);
    memcpy(pBuf, result.c_str(), byteLen);
    pBuf[chLen] = '\0';

    return pBuf;
}

자... 그럼 이걸 이용해서 지난 번에 다룬 MBR의 부트 코드를 덤프해 볼까요? ^^

C#으로 다루는 MBR(Master Boot Record)
; https://www.sysnet.pe.kr/2/0/10913

부트 코드가 16비트 real모드로 0x7c00 주소에 로드되어 실행된다는 점을 기반으로 다음과 같이 인자를 주어 덤프할 수 있습니다. (baseAddress는 0으로 주어도 무방합니다.)

MBR mbr;
bool result = MBR.TryParse(sector, out mbr);

if (result == true)
{
    DumpX86Code(mbr.BootCode);
    foreach (var part in mbr.Partitions)
    {
        Console.WriteLine(part);
    }
}

[DllImport("winlibudis86.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]
static extern string GetDisassemble(int bitMode, long baseAddress, byte[] input, int inputLen);

public void DumpX86Code(byte [] codes)
{
    string txt = GetDisassemble(16, 0x7c00, codes, codes.Length);
    Console.WriteLine(txt);
}

출력 결과는????

7c00 33c0 xor ax, ax
7c02 8ed0 mov ss, ax
7c04 bc007c mov sp, 0x7c00
7c07 8ec0 mov es, ax
7c09 8ed8 mov ds, ax
7c0b be007c mov si, 0x7c00
7c0e bf0006 mov di, 0x600
7c11 b90002 mov cx, 0x200
7c14 fc cld
7c15 f3a4 rep movsb
7c17 50 push ax
7c18 681c06 push 0x61c
7c1b cb retf
7c1c fb sti
7c1d b90400 mov cx, 0x4
7c20 bdbe07 mov bp, 0x7be
7c23 807e0000 cmp byte [bp], 0x0
7c27 7c0b jl 0x7c34
7c29 0f850e01 jnz 0x7d3b
7c2d 83c510 add bp, 0x10
7c30 e2f1 loop 0x7c23
7c32 cd18 int 0x18
7c34 885600 mov [bp], dl
7c37 55 push bp
7c38 c6461105 mov byte [bp+0x11], 0x5
7c3c c6461000 mov byte [bp+0x10], 0x0
7c40 b441 mov ah, 0x41
7c42 bbaa55 mov bx, 0x55aa
7c45 cd13 int 0x13
7c47 5d pop bp
7c48 720f jb 0x7c59
7c4a 81fb55aa cmp bx, 0xaa55
7c4e 7509 jnz 0x7c59
7c50 f7c10100 test cx, 0x1
7c54 7403 jz 0x7c59
7c56 fe4610 inc byte [bp+0x10]
7c59 6660 pushad
7c5b 807e1000 cmp byte [bp+0x10], 0x0
7c5f 7426 jz 0x7c87
7c61 666800000000 push 0x0
7c67 66ff7608 push dword [bp+0x8]
7c6b 680000 push 0x0
7c6e 68007c push 0x7c00
7c71 680100 push 0x1
7c74 681000 push 0x10
7c77 b442 mov ah, 0x42
7c79 8a5600 mov dl, [bp]
7c7c 8bf4 mov si, sp
7c7e cd13 int 0x13
7c80 9f lahf
7c81 83c410 add sp, 0x10
7c84 9e sahf
7c85 eb14 jmp 0x7c9b
7c87 b80102 mov ax, 0x201
7c8a bb007c mov bx, 0x7c00
7c8d 8a5600 mov dl, [bp]
7c90 8a7601 mov dh, [bp+0x1]
7c93 8a4e02 mov cl, [bp+0x2]
7c96 8a6e03 mov ch, [bp+0x3]
7c99 cd13 int 0x13
7c9b 6661 popad
7c9d 731c jae 0x7cbb
7c9f fe4e11 dec byte [bp+0x11]
7ca2 750c jnz 0x7cb0
7ca4 807e0080 cmp byte [bp], 0x80
7ca8 0f848a00 jz 0x7d36
7cac b280 mov dl, 0x80
7cae eb84 jmp 0x7c34
7cb0 55 push bp
7cb1 32e4 xor ah, ah
7cb3 8a5600 mov dl, [bp]
7cb6 cd13 int 0x13
7cb8 5d pop bp
7cb9 eb9e jmp 0x7c59
7cbb 813efe7d55aa cmp word [0x7dfe], 0xaa55
7cc1 756e jnz 0x7d31
7cc3 ff7600 push word [bp]
7cc6 e88d00 call 0x7d56
7cc9 7517 jnz 0x7ce2
7ccb fa cli
7ccc b0d1 mov al, 0xd1
7cce e664 out 0x64, al
7cd0 e88300 call 0x7d56
7cd3 b0df mov al, 0xdf
7cd5 e660 out 0x60, al
7cd7 e87c00 call 0x7d56
7cda b0ff mov al, 0xff
7cdc e664 out 0x64, al
7cde e87500 call 0x7d56
7ce1 fb sti
7ce2 b800bb mov ax, 0xbb00
7ce5 cd1a int 0x1a
7ce7 6623c0 and eax, eax
7cea 753b jnz 0x7d27
7cec 6681fb54435041 cmp ebx, 0x41504354
7cf3 7532 jnz 0x7d27
7cf5 81f90201 cmp cx, 0x102
7cf9 722c jb 0x7d27
7cfb 666807bb0000 push 0xbb07
7d01 666800020000 push 0x200
7d07 666808000000 push 0x8
7d0d 6653 push ebx
7d0f 6653 push ebx
7d11 6655 push ebp
7d13 666800000000 push 0x0
7d19 6668007c0000 push 0x7c00
7d1f 6661 popad
7d21 680000 push 0x0
7d24 07 pop es
7d25 cd1a int 0x1a
7d27 5a pop dx
7d28 32f6 xor dh, dh
7d2a ea007c0000 jmp word 0x0:0x7c00
7d2f cd18 int 0x18
7d31 a0b707 mov al, [0x7b7]
7d34 eb08 jmp 0x7d3e
7d36 a0b607 mov al, [0x7b6]
7d39 eb03 jmp 0x7d3e
7d3b a0b507 mov al, [0x7b5]
7d3e 32e4 xor ah, ah
7d40 050007 add ax, 0x700
7d43 8bf0 mov si, ax
7d45 ac lodsb
7d46 3c00 cmp al, 0x0
7d48 7409 jz 0x7d53
7d4a bb0700 mov bx, 0x7
7d4d b40e mov ah, 0xe
7d4f cd10 int 0x10
7d51 ebf2 jmp 0x7d45
7d53 f4 hlt
7d54 ebfd jmp 0x7d53
7d56 2bc9 sub cx, cx
7d58 e464 in al, 0x64
7d5a eb00 jmp 0x7d5c
7d5c 2402 and al, 0x2
7d5e e0f8 loopne 0x7d58
7d60 2402 and al, 0x2
7d62 c3 ret
7d63 49 dec cx
7d64 6e outsb
7d65 7661 jbe 0x7dc8
7d67 6c insb
7d68 6964207061 imul sp, [si+0x20], 0x6170
7d6d 7274 jb 0x7de3
7d6f 6974696f6e imul si, [si+0x69], 0x6e6f
7d74 207461 and [si+0x61], dh
7d77 626c65 bound bp, [si+0x65]
7d7a 004572 add [di+0x72], al
7d7d 726f jb 0x7dee
7d7f 7220 jb 0x7da1
7d81 6c insb
7d82 6f outsw
7d83 61 popa
7d84 64696e67206f imul bp, [fs:bp+0x67], 0x6f20
7d8a 7065 jo 0x7df1
7d8c 7261 jb 0x7def
7d8e 7469 jz 0x7df9
7d90 6e outsb
7d91 67207379 and [ebx+0x79], dh
7d95 7374 jae 0x7e0b
7d97 656d gs insw
7d99 004d69 add [di+0x69], cl
7d9c 7373 jae 0x7e11
7d9e 696e67206f imul bp, [bp+0x67], 0x6f20
7da3 7065 jo 0x7e0a
7da5 7261 jb 0x7e08
7da7 7469 jz 0x7e12
7da9 6e outsb
7daa 67207379 and [ebx+0x79], dh
7dae 7374 jae 0x7e24
7db0 656d gs insw
7db2 0000 add [bx+si], al
7db4 00637b add [bp+di+0x7b], ah
7db7 9ab5247c03 call word 0x37c:0x24b5
7dbc 0000 add [bx+si], al

(첨부한 파일은 Udis86 라이브러리에 제가 추가한 winlibudis86 Win32 DLL 프로젝트를 추가한 소스코드입니다.)




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]





[최초 등록일: ]
[최종 수정일: 3/9/2016 ]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer@outlook.com

비밀번호

댓글 쓴 사람
 




[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
12265정성태7/10/202013오류 유형: 629. Visual Studio - 웹 애플리케이션 실행 시 "Unable to connect to web server 'IIS Express'." 오류 발생
12264정성태7/9/202018오류 유형: 628. docker: Error response from daemon: Conflict. The container name "..." is already in use by container "...".
12261정성태7/9/2020150VS.NET IDE: 148. 윈도우 10에서 .NET Core 응용 프로그램을 리눅스 환경에서 실행하는 2가지 방법 - docker, WSL 2 [3]
12260정성태7/8/202057.NET Framework: 926. C# - ETW를 이용한 ThreadPool 스레드 감시파일 다운로드1
12259정성태7/8/202020오류 유형: 627. nvlddmkm.sys의 BAD_POOL_HEADER BSOD 문제
12258정성태7/8/202082기타: 77. DataDog APM 간략 소개
12257정성태7/7/202054.NET Framework: 925. C# - ETW를 이용한 Monitor Enter/Exit 감시파일 다운로드1
12256정성태7/7/202094.NET Framework: 924. C# - Reflection으로 변경할 수 없는 readonly 정적 필드 [4]
12255정성태7/6/202064.NET Framework: 923. C# - ETW(Event Tracing for Windows)를 이용한 Finalizer 실행 감시파일 다운로드1
12254정성태7/2/202036오류 유형: 626. git - REMOTE HOST IDENTIFICATION HAS CHANGED!
12253정성태7/2/2020107.NET Framework: 922. C# - .NET ThreadPool의 Local/Global Queue파일 다운로드1
12252정성태7/2/202085.NET Framework: 921. C# - I/O 스레드를 사용한 비동기 소켓 서버/클라이언트파일 다운로드2
12251정성태7/1/2020110.NET Framework: 920. C# - 파일의 비동기 처리 유무에 따른 스레드 상황파일 다운로드2
12250정성태7/1/2020317.NET Framework: 919. C# - 닷넷에서의 진정한 비동기 호출을 가능케 하는 I/O 스레드 사용법 [1]파일 다운로드1
12249정성태6/29/202035오류 유형: 625. Microsoft SQL Server 2019 RC1 Setup - 설치 제거 시 Warning 26003 오류 발생
12248정성태6/29/202033오류 유형: 624. SQL 서버 오류 - service-specific error code 17051
12247정성태6/29/2020129.NET Framework: 918. C# - 불린 형 상수를 반환값으로 포함하는 3항 연산자 사용 시 단축 표현 권장(IDE0075) [2]파일 다운로드1
12246정성태6/29/202067.NET Framework: 917. C# - USB 관련 ETW(Event Tracing for Windows)를 이용한 키보드 입력을 감지하는 방법
12245정성태6/25/2020223.NET Framework: 916. C# - Task.Yield 사용법 (2) [2]파일 다운로드1
12244정성태6/29/2020101.NET Framework: 915. ETW(Event Tracing for Windows)를 이용한 닷넷 프로그램의 내부 이벤트 활용파일 다운로드1
12243정성태6/23/202064VS.NET IDE: 147. Visual C++ 프로젝트 - .NET Core EXE를 "Debugger Type"으로 지원하는 기능 추가
12242정성태6/24/202039오류 유형: 623. AADSTS90072 - User account '...' from identity provider 'live.com' does not exist in tenant 'Microsoft Services'
12241정성태6/26/2020123.NET Framework: 914. C# - Task.Yield 사용법파일 다운로드1
12240정성태6/23/202094오류 유형: 622. 소켓 바인딩 시 "System.Net.Sockets.SocketException: An attempt was made to access a socket in a way forbidden by its access permissions" 오류 발생
12239정성태6/21/202069Linux: 30. (윈도우라면 DLL에 속하는) .so 파일이 텍스트로 구성된 사례
[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...