Last active
December 10, 2020 23:17
-
-
Save dbwodlf3/3f9ae0f11cf67cef4cbef7742f96f35c to your computer and use it in GitHub Desktop.
SMC_IN_LIFTED_LL
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| =============================================================================== | |
| SMC Codes in LL From Binary | |
| =============================================================================== | |
| X86, X64 Binary 파일로부터 Mcsema을 이용하여 Lifting된 LL 파일에 대하여 설명한다. | |
| 명령어 형태에 영향을 주는 기준 1. | |
| 1.1. NO-PIE SMC 코드 | |
| 1.2. PIE SMC 코드 | |
| 명령어 형태에 영향을 주는 기준 2. | |
| 2.1. Code 영역을 직접 수정는가. | |
| 2.2. Data 영역을 수정하고 해당 영역으로 실행흐름이 이동하는가. | |
| 주의! | |
| 어셈블리 | |
| 일반적으로 assembly는 GCC와 같은 -fPIE 옵션을 지원하지 않는 것으로 보인다. | |
| PIE 코드로 작성을 할려면, assembly를 작성할 때에 PIE 코드처럼 작성해야하는 것 같다. | |
| (추측. 확실하지 않음. 하지만 높은 확률로 그런 것 같다.) | |
| =============================================================================== | |
| 1. NO-PIE SMC 코드. | |
| =============================================================================== | |
| 1.1. 특징 | |
| smc14.c 코드의 경우가 대표적인 NO-PIE SMC 코드다. Binary 레벨에서 Dest Memory가 | |
| 명령어의 오퍼랜드로 literal하게 나타나 있음을 확인할 수 있다. 이는 리프팅된 코드에서 | |
| 도 적나라하게 드러난다. | |
| 1.2. binary 특징 | |
| Binary Example 1과 Binary Example 2에서 NO-PIE SMC를 확인할 수 있다. | |
| dest 의 operand 가 literal한 값임을 확인할 수 있다. | |
| 1.3. lifted ll 특징 | |
| Lifted LL Example 1과 Lifted LL Example 2에서 리프팅된 LL 파일을 확인할 수 있다. | |
| @data_${address} 에 쓰기 명령을 수행 하는 것을 확인할 수 있다. | |
| x86_smc1.s | |
| x86_smc2.s | |
| x86_smc3.s | |
| x86_smc4.s | |
| x86_smc4.s | |
| x86_smc5.s | |
| x86_smc6.s | |
| x86_smc7.s | |
| x86_smc8.s | |
| x86_smc9.s | |
| smc14.c | |
| smc15.c | |
| 위의 코드들이 NO-PIE SMC 코드에 해당한다. | |
| =============================================================================== | |
| 2. PIE SMC 코드. | |
| =============================================================================== | |
| 주의! | |
| 1. C 언어에서의 PIE의 영향을 받는 것은 Sequential 한 Memory 뿐이다. | |
| 2. 영향을 받는 것은 다음과 같다. 글로벌 변수(.data), 함수(.text), 상수(.rodata) | |
| 2.1. 특징 | |
| X86에서는 eip 레지스터를 offset으로 사용하는 명령어가 없으므로 call-pop trick을 | |
| 이용한다. (JMP-CALL-POP Techique) | |
| gcc의 경우 get_thunk_pc 프로시저를 사용하여 eip 레지스터 값을 얻고 이를 offset으로 | |
| 활용한다. clang의 경우에는 바로 다음 주소로 call 명령을 하고, pop 명령을 사용하여 | |
| 이를 offset으로 활용한다. | |
| lea 0xAddress(offset), $eax 같은 방식으로 사용한다. | |
| x64에서는 rip 레지스터를 offset으로 사용하는 명령어가 있으므로 call-pop trick을 | |
| 사용하지 않는다. (바로 명령어로 사용한다.) | |
| 2.2. binary 특징 | |
| 글로벌 변수(.data), 함수(.text), 상수(.rodata)와 관련된 명령이 있을 시에 오프셋 | |
| 을 활용하여 해당 값을 구한다. x64의 경우에는 lea 명령어 자체에 rip를 사용한다. | |
| lea 명령어의 offset으로 rip를 사용하느냐, 아니면 다른 레지스터를 사용하느냐의 | |
| 사소한 차이점이 존재한다. | |
| Binary Example 3과 Binary Example 4에서 x86과 x64의 SMC 명령이 유사하다는걸 | |
| 확인할 수 있다. | |
| Binary Example 5에서 PIE 에서 코드영역에 바로 쓰는 것을 살펴볼 수 있다. | |
| 2.3. lifted ll 특징 | |
| mcsema 에서는 최적화를 통하여 get_pc_thunk 같은 프로시저를 없애고, 직접 바로 | |
| 값을 정리한다. | |
| 2.3.1. 코드 영역 수정의 경우 -> register에 들어 있는 memory address 값에 store. | |
| 2.3.2. 함수 호출의 경우 -> Calling Convention 에 따라 @Reg 의 값을 변경후 함수 호출. | |
| (memcpy 같은 함수 호출에 적용 가능. AMD64에서 @RDI 레지스터를 확인.) | |
| 2.3.3. 포인터 함수 호출의 경우 -> 해당 address 값으로 @__remill_function_call. | |
| 각 Lifted LL Example 3, 4, 5에서 확인할 수 있다. | |
| (LL Example 4에 대한 적절한 예제는 아직 없음.. 만들어야 함. 추후 업데이트.) | |
| smc1.c | |
| smc2.c | |
| smc3.c | |
| smc4.c | |
| smc5.c | |
| smc6.c | |
| smc7.c | |
| smc8.c | |
| smc9.c | |
| smc10.c | |
| smc11.c | |
| smc12.c | |
| smc13.c | |
| smc16.c | |
| smc17.c | |
| smc18.c | |
| smc19.c | |
| 위의 코드들이 PIE SMC 코드에 해당한다. | |
| =============================================================================== | |
| 3. LL 명령어의 형태. | |
| =============================================================================== | |
| 설명설명... | |
| =============================================================================== | |
| Binary Examples | |
| =============================================================================== | |
| Example 1. | |
| smc14.c & gcc_m64_NO_PIE_smc14.objdump : 바로 쓰는 경우. | |
| ------------------------------------------------------------------------------- | |
| int main() | |
| { | |
| ... | |
| *(unsigned long long*)0x40051c = 0x9090909090909090; | |
| ... | |
| } | |
| => | |
| 00000000004004f7 <main>: | |
| ... | |
| 400505: b8 1c 05 40 00 mov $0x40051c,%eax | |
| 40050a: 48 ba 90 90 90 90 90 movabs $0x9090909090909090,%rdx | |
| 400511: 90 90 90 | |
| 400514: 48 89 10 mov %rdx,(%rax) | |
| ... | |
| =============================================================================== | |
| Example 2. | |
| x86_smc1.s & x86_smc1.objdump : 바로 쓰는 경우. | |
| ------------------------------------------------------------------------------- | |
| ... | |
| key: | |
| add edx, 0 ; Store next Fibonacci number to edx(Fn + Fn-1 = Fn+1) | |
| mov al, bl ; store Fn fibonachi value into al. | |
| mov [key+2], al | |
| ... | |
| => | |
| ... | |
| 08048079 <key>: | |
| 8048079: 83 c2 00 add $0x0,%edx | |
| 804807c: 88 d8 mov %bl,%al | |
| 804807e: a2 7b 80 04 08 mov %al,0x804807b | |
| ... | |
| =============================================================================== | |
| Example 3. | |
| smc12.c & gcc_m64_PIE_smc12.objdump : amd64 에서의 PIE | |
| ------------------------------------------------------------------------------- | |
| ... | |
| char code[] = | |
| "\xb8\x01\x00\x00\x00" | |
| "\xcd\x80"; | |
| ... | |
| int main(){ | |
| ... | |
| ((void(*)())code)(); | |
| ... | |
| return 0; | |
| } | |
| => | |
| ... | |
| 00000000000006fa <main>: | |
| ... | |
| 728: 48 8d 55 f0 lea -0x10(%rbp),%rdx | |
| 72c: b8 00 00 00 00 mov $0x0,%eax | |
| 731: ff d2 callq *%rdx | |
| ... | |
| =============================================================================== | |
| Example 4. | |
| smc12.c & gcc_m32_PIE_smc12.objdump : x86 에서의 PIE. | |
| ------------------------------------------------------------------------------- | |
| ... | |
| char code[] = | |
| "\xb8\x01\x00\x00\x00" | |
| "\xcd\x80"; | |
| ... | |
| int main(){ | |
| ... | |
| ((void(*)())code)(); | |
| ... | |
| return 0; | |
| } | |
| => | |
| ... | |
| 00000000000006fa <main>: | |
| ... | |
| 728: 48 8d 55 f0 lea -0x10(%rbp),%rdx | |
| 72c: b8 00 00 00 00 mov $0x0,%eax | |
| 731: ff d2 callq *%rdx | |
| ... | |
| =============================================================================== | |
| Example 5. | |
| smc20.c & gcc_m64_PIE_smc20.objdump : PIE 에서 . | |
| ------------------------------------------------------------------------------- | |
| ... | |
| char code[] = | |
| "\xb8\x01\x00\x00\x00" | |
| "\xcd\x80"; | |
| ... | |
| int main() | |
| { | |
| ... | |
| *(unsigned long long*)(main + 0x29) = 0x9090909090909090; | |
| ... | |
| } | |
| => | |
| ... | |
| 000000000000064a <main>: | |
| ... | |
| 65a: 48 8d 05 12 00 00 00 lea 0x12(%rip),%rax # 673 <main+0x29> | |
| 661: 48 ba 90 90 90 90 90 movabs $0x9090909090909090,%rdx | |
| 668: 90 90 90 | |
| 66b: 48 89 10 mov %rdx,(%rax) | |
| ... | |
| =============================================================================== | |
| =============================================================================== | |
| Lifted LL Examples | |
| =============================================================================== | |
| Example 1. | |
| gcc_m64_NO_PIE.objdump & gcc_m64_NO_PIE_smc14.ll : 바로 쓰는 경우. | |
| ------------------------------------------------------------------------------- | |
| 00000000004004f7 <main>: | |
| ... | |
| 400505: b8 1c 05 40 00 mov $0x40051c,%eax | |
| 40050a: 48 ba 90 90 90 90 90 movabs $0x9090909090909090,%rdx | |
| 400511: 90 90 90 | |
| 400514: 48 89 10 mov %rdx,(%rax) | |
| ... | |
| => | |
| define internal %struct.Memory* @sub_4004f7_main(%struct.State* noalias nonnull %state, i64 %pc, %struct.Memory* noalias %memory) #10 { | |
| ... | |
| store i64 -8029759185026510704, i64* bitcast (i8* @data_40051c to i64*) | |
| ... | |
| } | |
| =============================================================================== | |
| Example 2. | |
| x86_smc1.objdump & x86_smc1.out.ll : 바로 쓰는 경우. | |
| Example 2의 경우에 조금 smc 코드상에 문제가 있음.. trivial 한 문제. 나중에 수정. | |
| 크게 변하지 않음. dest 위치에 memory 값이 왔다는게 중요. | |
| ------------------------------------------------------------------------------- | |
| ... | |
| 08048079 <key>: | |
| 8048079: 83 c2 00 add $0x0,%edx | |
| 804807c: 88 d8 mov %bl,%al | |
| 804807e: a2 7b 80 04 08 mov %al,0x804807b | |
| ... | |
| => | |
| define internal %struct.Memory* @sub_8048060_main(%struct.State* noalias nonnull %state, i32 %pc, %struct.Memory* noalias %memory) #8 { | |
| ... | |
| store i8 1, i8* @data_804807b | |
| ... | |
| } | |
| =============================================================================== | |
| Example 3. | |
| gcc_m64_PIE_smc20.objdump & gcc_m64_PIE_smc20.ll : PIE 에서 코드영역 바로 쓰기 | |
| ------------------------------------------------------------------------------- | |
| ... | |
| 000000000000064a <main>: | |
| ... | |
| 65a: 48 8d 05 12 00 00 00 lea 0x12(%rip),%rax # 673 <main+0x29> | |
| 661: 48 ba 90 90 90 90 90 movabs $0x9090909090909090,%rdx | |
| 668: 90 90 90 | |
| 66b: 48 89 10 mov %rdx,(%rax) | |
| ... | |
| => | |
| define internal %struct.Memory* @sub_64a_main(%struct.State* noalias nonnull %state, i64 %pc, %struct.Memory* noalias %memory) #10 { | |
| ... | |
| store i64 -8029759185026510704, i64* bitcast (i8* @data_673 to i64*) | |
| ... | |
| } | |
| =============================================================================== | |
| Example 5. | |
| gcc_m64_PIE_smc13.objdump & gcc_m64_PIE_smc13.ll : 데이터로 함수포인터 호출 | |
| ------------------------------------------------------------------------------- | |
| ... | |
| 00000000000006fa <main>: | |
| ... | |
| 728: 48 8d 55 f0 lea -0x10(%rbp),%rdx | |
| 72c: b8 00 00 00 00 mov $0x0,%eax | |
| 731: ff d2 callq *%rdx | |
| ... | |
| => | |
| define internal %struct.Memory* @sub_6fa_main(%struct.State* noalias nonnull %state, i64 %pc, %struct.Memory* noalias %memory) #10 { | |
| ... | |
| %16 = load i64, i64* @RBP_2328_55a213c181c8 | |
| %17 = sub i64 %16, 16 | |
| %21 = call %struct.Memory* @__remill_function_call(%struct.State* @__mcsema_reg_state, i64 %17, %struct.Memory* %15) | |
| ... | |
| } | |
| =============================================================================== |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment