Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
(연관된 글이 2개 있습니다.)

머신 바이트 배열로부터 역어셈블해주는 라이브러리 - 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 프로젝트를 추가한 소스코드입니다.)




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

[연관 글]






[최초 등록일: ]
[최종 수정일: 7/10/2021]

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

비밀번호

댓글 작성자
 




... [16]  17  18  19  20  21  22  23  24  25  26  27  28  29  30  ...
NoWriterDateCnt.TitleFile(s)
13223정성태1/20/20234288오류 유형: 838. RDP 연결 오류 - The two computers couldn't connect in the amount of time allotted
13222정성태1/20/20233945개발 환경 구성: 657. WSL - DockerDesktop.vhdx 파일 위치를 옮기는 방법
13221정성태1/19/20234169Linux: 57. C# - 리눅스 프로세스 메모리 정보파일 다운로드1
13220정성태1/19/20234325오류 유형: 837. NETSDK1045 The current .NET SDK does not support targeting .NET ...
13219정성태1/18/20233889Windows: 220. 네트워크의 인터넷 접속 가능 여부에 대한 판단 기준
13218정성태1/17/20233826VS.NET IDE: 178. Visual Studio 17.5 (Preview 2) - 포트 터널링을 이용한 웹 응용 프로그램의 외부 접근 허용
13217정성태1/13/20234423디버깅 기술: 185. windbg - 64비트 운영체제에서 작업 관리자로 뜬 32비트 프로세스의 덤프를 sos로 디버깅하는 방법
13216정성태1/12/20234673디버깅 기술: 184. windbg - 32비트 프로세스의 메모리 덤프인 경우 !peb 명령어로 나타나지 않는 환경 변수
13215정성태1/11/20236188Linux: 56. 리눅스 - /proc/pid/stat 정보를 이용해 프로세스의 CPU 사용량 구하는 방법 [1]
13214정성태1/10/20235758.NET Framework: 2087. .NET 6부터 SourceGenerator와 통합된 System.Text.Json [1]파일 다운로드1
13213정성태1/9/20235290오류 유형: 836. docker 이미지 빌드 시 "RUN apt install ..." 명령어가 실패하는 이유
13212정성태1/8/20235055기타: 85. 단정도/배정도 부동 소수점의 정밀도(Precision)에 따른 형변환 손실
13211정성태1/6/20235114웹: 42. (https가 아닌) http 다운로드를 막는 웹 브라우저
13210정성태1/5/20234146Windows: 219. 윈도우 x64의 경우 0x00000000`7ffe0000 아래의 주소는 왜 사용하지 않을까요?
13209정성태1/4/20234048Windows: 218. 왜 윈도우에서 가상 메모리 공간은 64KB 정렬이 된 걸까요?
13208정성태1/3/20233994.NET Framework: 2086. C# - Windows 운영체제의 2MB Large 페이지 크기 할당 방법파일 다운로드1
13207정성태12/26/20224294.NET Framework: 2085. C# - gpedit.msc의 "User Rights Assignment" 특권을 코드로 설정/해제하는 방법파일 다운로드1
13206정성태12/24/20224509.NET Framework: 2084. C# - GetTokenInformation으로 사용자 SID(Security identifiers) 구하는 방법 [3]파일 다운로드1
13205정성태12/24/20224890.NET Framework: 2083. C# - C++과의 연동을 위한 구조체의 fixed 배열 필드 사용 (2)파일 다운로드1
13204정성태12/22/20224175.NET Framework: 2082. C# - (LSA_UNICODE_STRING 예제로) CustomMarshaler 사용법파일 다운로드1
13203정성태12/22/20224332.NET Framework: 2081. C# Interop 예제 - (LSA_UNICODE_STRING 예제로) 구조체를 C++에 전달하는 방법파일 다운로드1
13202정성태12/21/20224728기타: 84. 직렬화로 설명하는 Little/Big Endian파일 다운로드1
13201정성태12/20/20225352오류 유형: 835. PyCharm 사용 시 C 드라이브 용량 부족
13200정성태12/19/20224211오류 유형: 834. 이벤트 로그 - SSL Certificate Settings created by an admin process for endpoint
13199정성태12/19/20224495개발 환경 구성: 656. Internal Network 유형의 스위치로 공유한 Hyper-V의 VM과 호스트가 통신이 안 되는 경우
13198정성태12/18/20224376.NET Framework: 2080. C# - Microsoft.XmlSerializer.Generator 처리 없이 XmlSerializer 생성자를 예외 없이 사용하고 싶다면?파일 다운로드1
... [16]  17  18  19  20  21  22  23  24  25  26  27  28  29  30  ...