জিসিসি এবং এলডিতে পজিশন-ইন্ডিপেন্ডেট এক্সিকিউটেবলের জন্য -fPIE বিকল্পটি কী?


উত্তর:


100

পিআইই হ'ল এক্সিকিউটেবল ফাইলগুলিতে অ্যাড্রেস স্পেস লেআউট র্যান্ডমাইজেশন (এএসএলআর) সমর্থন করে।

পিআইই মোডটি তৈরি হওয়ার আগে, প্রোগ্রামটির এক্সিকিউটেবল মেমরির এলোমেলো ঠিকানায় রাখা যায় না, কেবলমাত্র অবস্থানের স্বাধীন কোড (পিআইসি) ডায়নামিক লাইব্রেরিগুলি এলোমেলো অফসেটে স্থানান্তরিত করা যেতে পারে could এটি ডায়নামিক লাইব্রেরিগুলির জন্য পিআইসি যেভাবে কাজ করে তার মতো কাজ করে, পার্থক্যটি হ'ল একটি প্রক্রিয়া লিংকেজ টেবিল (পিএলটি) তৈরি করা হয় না, পরিবর্তে পিসি-আপেক্ষিক স্থানান্তর ব্যবহৃত হয়।

জিসিসি / লঙ্কারগুলিতে পিআইই সমর্থন সক্ষম করার পরে, প্রোগ্রামের মূল অংশটি সংকলিত হয় এবং অবস্থান-স্বাধীন কোড হিসাবে সংযুক্ত করা হয়। একটি গতিশীল লিঙ্কার গতিশীল লাইব্রেরির মতোই প্রোগ্রাম মডিউলে পুরো স্থান পরিবর্তন প্রক্রিয়াজাতকরণ করে। গ্লোবাল অফসেট টেবিল (জিওটি) এর মাধ্যমে গ্লোবাল ডেটার যে কোনও ব্যবহার অ্যাক্সেসে রূপান্তরিত হয় এবং জিওটি স্থানান্তর যুক্ত হয়।

এই ওপেনবিএসডি পিআইই উপস্থাপনায় পিআইই ভালভাবে বর্ণনা করা হয়েছে ।

ফাংশনগুলির পরিবর্তনগুলি এই স্লাইডে দেখানো হয়েছে (পিআইই বনাম পিআইসি)।

x86 পিক বনাম পাই

স্থানীয় গ্লোবাল ভেরিয়েবল এবং ফাংশন পাইতে অনুকূলিত হয়

বাহ্যিক গ্লোবাল ভেরিয়েবল এবং ফাংশনগুলি পিকের মতো

এবং এই স্লাইডে (PIE বনাম পুরানো-শৈলীর লিঙ্কিং)

x86 পাই বনাম কোনও পতাকা (স্থির)

স্থানীয় গ্লোবাল ভেরিয়েবল এবং ফাংশন স্থির সমান

বাহ্যিক গ্লোবাল ভেরিয়েবল এবং ফাংশনগুলি পিকের মতো

দ্রষ্টব্য, PIE এর সাথে বেমানান হতে পারে -static


4
এছাড়াও উইকিপিডিয়া: en.wikipedia.org/wiki/...
osgx

4
কেন -পি এবং -স্ট্যাটিকগুলি এআরএমের সাথে সামঞ্জস্যপূর্ণ এবং x86 এ সামঞ্জস্যপূর্ণ নয়? আমার তাই প্রশ্ন: stackoverflow.com/questions/27082959/...
4ntoine

56

সর্বনিম্ন চলমান উদাহরণ: জিডিবি দু'বার নির্বাহযোগ্য

যারা কিছু পদক্ষেপ দেখতে চান তাদের জন্য আসুন আমরা পিআইই এক্সিকিউটেবলের উপর ASLR এর কাজ দেখি এবং রানগুলি জুড়ে ঠিকানাগুলি পরিবর্তন করি:

main.c

#include <stdio.h>

int main(void) {
    puts("hello");
}

main.sh

#!/usr/bin/env bash
echo 2 | sudo tee /proc/sys/kernel/randomize_va_space
for pie in no-pie pie; do
  exe="${pie}.out"
  gcc -O0 -std=c99 "-${pie}" "-f${pie}" -ggdb3 -o "$exe" main.c
  gdb -batch -nh \
    -ex 'set disable-randomization off' \
    -ex 'break main' \
    -ex 'run' \
    -ex 'printf "pc = 0x%llx\n", (long  long unsigned)$pc' \
    -ex 'run' \
    -ex 'printf "pc = 0x%llx\n", (long  long unsigned)$pc' \
    "./$exe" \
  ;
  echo
  echo
done

যাঁর সাথে রয়েছে তার জন্য -no-pie, সবকিছু বিরক্তিকর:

Breakpoint 1 at 0x401126: file main.c, line 4.

Breakpoint 1, main () at main.c:4
4           puts("hello");
pc = 0x401126

Breakpoint 1, main () at main.c:4
4           puts("hello");
pc = 0x401126

সম্পাদন শুরুর আগে break mainএকটি ব্রেকপয়েন্ট সেট করে 0x401126

তারপরে, উভয় ফাঁসি কার্যকর করার সময়, runঠিকানায় থামে 0x401126

সঙ্গে এক -pieকিন্তু আরো অনেক আকর্ষণীয় হল:

Breakpoint 1 at 0x1139: file main.c, line 4.

Breakpoint 1, main () at main.c:4
4           puts("hello");
pc = 0x5630df2d6139

Breakpoint 1, main () at main.c:4
4           puts("hello");
pc = 0x55763ab2e139

মৃত্যুদন্ড শুরু করার আগে, শুধু GDB একটি "ডামি" ঠিকানাটি যে এক্সিকিউটেবল উপস্থিত লাগে: 0x1139

এটি আরম্ভ করার পরে, জিডিবি বুদ্ধিমানভাবে লক্ষ্য করেছে যে গতিশীল লোডার প্রোগ্রামটিকে একটি অন্য স্থানে রেখেছিল এবং প্রথম বিরতিটি বন্ধ হয়ে যায় 0x5630df2d6139

তারপরে, দ্বিতীয় রানটিও বুদ্ধিমানের সাথে লক্ষ্য করল যে এক্সিকিউটেবলটি আবার সরে গেছে, এবং শেষ হয়ে গেল 0x55763ab2e139

echo 2 | sudo tee /proc/sys/kernel/randomize_va_spaceASLR চালু রয়েছে তা নিশ্চিত করে (উবুন্টু 17.10 এ ডিফল্ট): আমি কীভাবে অস্থায়ীভাবে ASLR (ঠিকানা স্থানের বিন্যাস র্যান্ডমাইজেশন) অক্ষম করতে পারি? | উবুন্টুকে জিজ্ঞাসা করুন

set disable-randomization offঅন্যথায় প্রয়োজন হয় জিডিবি, নাম অনুসারে, ডিবাগিংয়ের অভিজ্ঞতার উন্নতি করার জন্য রানের জুড়ে নির্দিষ্ট ঠিকানা দেওয়ার জন্য ডিফল্টরূপে প্রক্রিয়াটির জন্য এএসএলআর বন্ধ করে দেয়: জিডিবি ঠিকানা এবং "প্রকৃত" ঠিকানাগুলির মধ্যে পার্থক্য? | স্ট্যাক ওভারফ্লো

readelf বিশ্লেষণ

তদতিরিক্ত, আমরা এটি পর্যবেক্ষণ করতে পারি:

readelf -s ./no-pie.out | grep main

আসল রানটাইম লোড ঠিকানা দেয় (পিসি নিম্নলিখিত নির্দেশাবলী 4 বাইট পরে নির্দেশিত):

64: 0000000000401122    21 FUNC    GLOBAL DEFAULT   13 main

যখন:

readelf -s ./pie.out | grep main

একটি অফসেট দেয়:

65: 0000000000001135    23 FUNC    GLOBAL DEFAULT   14 main

এএসএলআর বন্ধ করে (উভয় randomize_va_spaceবা দিয়ে set disable-randomization off), জিডিবি সর্বদা mainঠিকানা দেয় : 0x5555555547a9তাই আমরা অনুমান করি যে -pieঠিকানাটি এর থেকে রচিত:

0x555555554000 + random offset + symbol offset (79a)

TODO যেখানে 0x555555554000 হার্ড লিনাক্স কার্নেল / glibc লোডার / কোথাও কোডড আছে? লিনাক্সে পিআইই এক্সিকিউটেবলের পাঠ্য বিভাগের ঠিকানা কীভাবে নির্ধারণ করা হয়?

ন্যূনতম সমাবেশ উদাহরণ

আর একটি দুর্দান্ত জিনিস যা আমরা করতে পারি তা হ'ল পিআইই মানে কী তা আরও দৃ concrete়তার সাথে বোঝার জন্য কিছু অ্যাসেম্বলি কোড নিয়ে ঘুরে বেড়ানো।

আমরা এটি লিনাক্স x86_64 ফ্রিস্ট্যান্ডিং অ্যাসেম্বলি হ্যালো ওয়ার্ল্ডের মাধ্যমে করতে পারি:

main.S

.text
.global _start
_start:
asm_main_after_prologue:
    /* write */
    mov $1, %rax   /* syscall number */
    mov $1, %rdi   /* stdout */
    mov $msg, %rsi  /* buffer */
    mov $len, %rdx /* len */
    syscall

    /* exit */
    mov $60, %rax   /* syscall number */
    mov $0, %rdi    /* exit status */
    syscall
msg:
    .ascii "hello\n"
len = . - msg

গিটহাব উজানের দিকে

এবং এটি একত্রিত হয় এবং এর সাথে সূক্ষ্মভাবে চলে:

as -o main.o main.S
ld -o main.out main.o
./main.out

তবে, আমরা যদি এটির সাথে পিআইই হিসাবে লিঙ্ক করার চেষ্টা করি (তবে --no-dynamic-linkerএখানে বর্ণিত হিসাবে প্রয়োজনীয়: লিনাক্সে কীভাবে একটি স্ট্যাটিকালি লিঙ্কড পজিশন স্বাধীন এক্সিকিউটেবল ইএলএফ তৈরি করতে পারি? ):

ld --no-dynamic-linker -pie -o main.out main.o

তারপরে লিঙ্কটি ব্যর্থ হবে:

ld: main.o: relocation R_X86_64_32S against `.text' can not be used when making a PIE object; recompile with -fPIC
ld: final link failed: nonrepresentable section on output

কারণ লাইন:

mov $msg, %rsi  /* buffer */

movঅপারেন্ডে বার্তাটির ঠিকানাটি হার্ডকোড করে এবং তাই অবস্থানটি স্বাধীন নয় position

যদি আমরা পরিবর্তে এটি একটি অবস্থানের মতো স্বতন্ত্র উপায়ে লিখি:

lea msg(%rip), %rsi

তারপরে পিআইই লিঙ্কটি সূক্ষ্মভাবে কাজ করে এবং জিডিবি আমাদের দেখায় যে এক্সিকিউটেবলটি প্রতিবার মেমরিতে পৃথক স্থানে লোড হয় get

এখানে পার্থক্যটি হ'ল সিন্টেক্সের কারণে বর্তমান পিসি leaঠিকানার সাথে msgসম্পর্কিত ঠিকানাটি এনকোড করা হয়েছে rip, এছাড়াও দেখুন: 64৪-বিট বিধানসভা প্রোগ্রামে আরআইপি রিলেটিভ অ্যাড্রেসিং কীভাবে ব্যবহার করবেন?

উভয় সংস্করণকে এগুলি ছড়িয়ে দিয়ে আমরা এটিও বের করতে পারি:

objdump -S main.o

যা যথাক্রমে দেয়:

e:   48 c7 c6 00 00 00 00    mov    $0x0,%rsi
e:   48 8d 35 19 00 00 00    lea    0x19(%rip),%rsi        # 2e <msg>

000000000000002e <msg>:
  2e:   68 65 6c 6c 6f          pushq  $0x6f6c6c65

সুতরাং আমরা স্পষ্টভাবে দেখতে পাই যে leaইতিমধ্যে msgবর্তমান ঠিকানা + 0x19 হিসাবে এনকোডের পুরো সঠিক ঠিকানা রয়েছে ।

movসংস্করণ কিন্তু করতে ঠিকানা সেট করেছে 00 00 00 00, যার মানে একটি স্থানান্তরের সেখানে সম্পাদিত হবে: linkers কি করবেন? রহস্যপূর্ণ R_X86_64_32Sমধ্যে ldত্রুটি বার্তা স্থানান্তরের প্রকৃত যে ধরনের প্রয়োজন ছিল এবং যা পাই এক্সেকিউটেবল ঘটতে পারে না।

আর একটি মজাদার জিনিস যা আমরা করতে পারি তা হ'ল msgডেটা বিভাগে .textরেখে দেওয়া:

.data
msg:
    .ascii "hello\n"
len = . - msg

এখন এতে .oএকত্রিত হন:

e:   48 8d 35 00 00 00 00    lea    0x0(%rip),%rsi        # 15 <_start+0x15>

সুতরাং এখন আরআইপি অফসেট 0, এবং আমরা অনুমান করি যে এসেম্বেলারের দ্বারা একটি স্থান পরিবর্তন করার জন্য অনুরোধ করা হয়েছে। আমরা এটি দিয়ে নিশ্চিত করি:

readelf -r main.o

যা দেয়:

Relocation section '.rela.text' at offset 0x160 contains 1 entry:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000000011  000200000002 R_X86_64_PC32     0000000000000000 .data - 4

তাই পরিষ্কারভাবে R_X86_64_PC32একটি পিসি আপেক্ষিক স্থানান্তর যা ldPIE এক্সিকিউটেবলের জন্য পরিচালনা করতে পারে।

এই পরীক্ষাটি আমাদের শিখিয়েছিল যে লিঙ্কার নিজেই প্রোগ্রামটি পরীক্ষা করে পিআইই হতে পারে এবং এটি হিসাবে চিহ্নিত করে।

তারপরে জিসিসির সাথে সংকলন করার সময়, -pieজিসিসিকে অবস্থান স্বাধীন সমাবেশ তৈরি করতে বলে।

তবে আমরা যদি নিজেরাই সমাবেশ লিখি তবে আমাদের অবশ্যই ম্যানুয়ালি নিশ্চিত করতে হবে যে আমরা অবস্থানের স্বাধীনতা অর্জন করেছি।

এআরএমভি 8 আর্চ 64 এ, এডিআর নির্দেশের মাধ্যমে অবস্থান স্বাধীন হ্যালো ওয়ার্ল্ড অর্জন করা যেতে পারে ।

কোনও ইএলএফ অবস্থান স্বাধীন কিনা তা কীভাবে নির্ধারণ করবেন?

এটি কেবল জিডিবি দিয়ে চালানো ছাড়াও কয়েকটি স্থিতিশীল পদ্ধতিতে এখানে উল্লেখ করা হয়েছে:

উবুন্টুতে পরীক্ষা করা হয়েছে 18.10।


4
হাই সিরো! আপনি কি এএসএলআর-অফ পাই-অন স্ট্রিং ঠিকানার জন্য আলাদা প্রশ্ন তৈরি করতে এবং এটি এখানে লিঙ্ক করতে পারেন?
osgx

4
@osgx সম্পন্ন হয়েছে। আপনি কি ইতিমধ্যে জানেন বা আপনি উড়তে এটি খনন করতে যাচ্ছেন? :-) আপনি যখন সেখানে ছিলেন, লিনাক্স কার্নেল / ডিন লোডার কীভাবে পিআইই আছে কি না তা নির্ধারণ করে তা বর্ণনা করা ভাল: unix.stackexchange.com/questions/89211/…
Ciro Santilli 郝海东 冠状 病 六四 事件法轮功

আমি ইতিমধ্যে জানি না, তবে আমি জানি যে এটি গ্লিবিসি - গ্লিবসি / এল্ফ গিথুব / ল্যাটেরা / গ্লিবসি / ট্রি / মাস্টার / বেল্ট (যদি অনুবাদক এখনও ld-linux.so থাকে) থেকে খনন করা উচিত । তিন বছর আগে বাসিল না 0x55555555 সম্পর্কে নিশ্চিত ছিল stackoverflow.com/questions/29856044 , কিন্তু যে প্রশ্নের নিজেই ld.so, তাই কার্নেলের মধ্যে খনন ঠিকানা শুরু সম্পর্কে ছিল FS / binfmt_elf.c বা readelf / objdump এবং linker স্ক্রিপ্ট।
osgx
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.