디스어셈블 주소지 질문

송파구최고존엄의 이미지

특정 파일을 디스어셈으로 보던 도중 나타나는 주소지와 실제 파일의 오프셋이 다른것으로 확인됩니다.

아래를 보면 main의 주소지가 04 라는 값이 붙어있는데 이게 주소 방식 차이때문이라고 알고있습니다.

(실제 파일주소지 620)

aarch64 gcc 컴파일러를 사용했는데 이것을 실제 파일 offset과 동일한 주소지로 사용될수 있도록

처리가능한 명령어가 있을까요 ?

0000000000400620 :
400620: d10043ff sub sp, sp, #0x10
400624: b9000fe0 str w0, [sp, #12]
400628: f90003e1 str x1,  
40062c: 12800000 mov w0, #0xffffffff
400630: 910043ff add sp, sp, #0x10
400634: d65f03c0 ret
400638: d503201f nop
40063c: d503201f nop

익명 사용자의 이미지

"main의 주소지가 04 라는 값이 붙어있다" 가 무슨말인가요?
400620 주소 코드가 스택 확장하는거 보니까 main 시작점 아닌가요?

chanik의 이미지

왜 0x400000 오프셋에 로드되는지 물으시는 것 같은데요. "Computing offset of a function in memory" 질문에 대한 누군가의 답변이 힌트가 될 지도 모르겠습니다. 저는 aarch64 시스템이 없어서 그냥 Ubuntu-20.04 x86_64 환경에서 따라해봤습니다.

https://stackoverflow.com/a/37932094

$ cat t.c
#include <stdio.h>
int main(void)
{
  printf("%p\n", main);
  return 0;
}
$ gcc -o t1 t.c -no-pie
$ gcc -o t2 t.c -pie
$ objdump -t t1 | grep ' main'
0000000000401136 g     F .text  0000000000000027              main
$ objdump -t t2 | grep ' main'
0000000000001149 g     F .text  0000000000000027              main

-pie 는 position independent executable로 만드는 옵션이라고 하고, 제 시스템의 gcc는 -pie 가 기본옵션인지 굳이 -no-pie 옵션을 줘야 fixed load address 바이너리가 만들어졌습니다. -no-pie 바이너리는 0x400000 오프셋이 추가돼있고, -pie 바이너리는 그렇지 않은 것이 보이죠.

실행해보면 아래와 같이 -no-pie 바이너리는 늘 고정된 가상주소에 로드되고, -pie 바이너리는 매번 다른 오프셋으로 로드됩니다 (랜덤으로 로드위치가 정해지는건 해킹을 어렵게 하기 위함인 것으로 압니다. 그래서 -pie가 기본값이 된건가 싶네요)

$ ./t1
0x401136
$ ./t1
0x401136
$ ./t1
0x401136
$ ./t1
0x401136
$ ./t2
0x56065292c149
$ ./t2
0x55ef7c661149
$ ./t2
0x55b5e5808149
$ ./t2
0x5601a99de149

지금 쓰시는 시스템에서는 기본값이 -no-pie 이거나 해당 바이너리가 -no-pie로 빌드된 것이 아닌가 싶고, -pie 옵션을 줘서 position independent executable로 만들면 0x400000 오프셋이 사라질수도 있겠습니다.

chanik의 이미지

호기심이 생겨 좀 더 찾아보니, 베이스오프셋 적용은 링커에 의해 이뤄지며 /usr/lib/x86_64-linux-gnu/ldscripts/ 에 있는 링커 스크립트들에서 볼 수 있군요. 각 스크립트에서 __executable_start 문자열을 grep해봐도 되고, 아래와 같이 ld 명령을 통해 확인해볼수도 있네요.

PIE(Position Independent Executable)가 아닌 바이너리를 만들때는 x86(gcc -m32), x86_64(-m64), x32(-mx32) 상황에 따라 각각 아래와 같이 미리 정해진 베이스 오프셋이 적용되고 실행시에도 이렇게 정해진 동일한 가상주소로 매번 로드되는 반면,

$ ld -melf_i386 --verbose | grep __executable_start
  PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x08048000)); . = SEGMENT_START("text-segment", 0x08048000) + SIZEOF_HEADERS;
$ ld -melf_x86_64 --verbose | grep __executable_start
  PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
$ ld -melf32_x86_64 --verbose | grep __executable_start
  PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;

-pie 옵션을 주어 PIE를 만들때는 아래와 같이 링크시에 따로 베이스 오프셋이 적용되지 않으며, 이렇게 만들어진 바이너리는 실행시마다 ASLR(Address Space Layout Randomization)에 의해 랜덤선택된 베이스주소로 로드되는 식이군요. PIE 바이너리에 대한 ASLR은 오래된 centos5에도 적용돼 있었습니다.

$ ld -melf_i386 -pie --verbose | grep __executable_start
  PROVIDE (__executable_start = SEGMENT_START("text-segment", 0)); . = SEGMENT_START("text-segment", 0) + SIZEOF_HEADERS;
$ ld -melf_x86_64 -pie --verbose | grep __executable_start
  PROVIDE (__executable_start = SEGMENT_START("text-segment", 0)); . = SEGMENT_START("text-segment", 0) + SIZEOF_HEADERS;
$ ld -melf32_x86_64 -pie --verbose | grep __executable_start
  PROVIDE (__executable_start = SEGMENT_START("text-segment", 0)); . = SEGMENT_START("text-segment", 0) + SIZEOF_HEADERS;

아래의 페이지를 보니 aarch64의 링커 스크립트도 비슷하군요. x86_64 시스템처럼 기본 베이스 오프셋이 0x400000이네요.

https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/+/master/aarch64-linux-android/lib/ldscripts/aarch64elf.x

/* Default linker script, for normal executables */
-- 중간생략 --
  PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x00400000)); . = SEGMENT_START("text-segment", 0x00400000);

https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/+/master/aarch64-linux-android/lib/ldscripts/aarch64elf.xd

/* Script for ld -pie: link position independent executable */
-- 중간생략 --
  PROVIDE (__executable_start = SEGMENT_START("text-segment", 0)); . = SEGMENT_START("text-segment", 0) + SIZEOF_HEADERS;

Necromancer의 이미지

os에서 실행파일을 그냥 load하고 call 하지 않습니다.

relocation이라고 해서 실행파일 올린 뒤에 실행파일이 올라간 base address에 따라 실행파일 내부의 코드에 적혀있는 address를 실제 load된 address에 맞게 변환하는 작업이 있습니다.

Written By the Black Knight of Destruction

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.