Phase 13: Tools & Protocols

Verileri ve Tipleri Geri Almak: Strukt, Array, C++ Nesneleri ve DWARF

Bir dekompiler izleri a->balancebir tip masası olduğunda ve *(int *)(param_1 + 4)Bu ders, girişlerden tablo oluşturur, DWARF 5'ten gerçek olanı okuyor ve iki tarafın nerede anlaştığını gösterir.

Type: Build

Languages: Python, TypeScript, C, C++, x86-64 assembly

Prerequisites: Phase 13 · 33 (disassembly and control flow), Phase 13 · 34 (lifting to pseudocode)

Time: ~140 minutes

Öğrenme Hedefleri

  • Intel SDM adresleme kurallarından bir struct üyesi erişimi temel kayıt artı yer değiştirme olarak ve bir dizi erişimi temel artı indeks zaman adım olarak okuyun.
  • Sistem V uyum kurallarını el ile uygulayın struct accountve her bir boytu açıklayın.
  • Bir listedeki erişimi her bir alanın karşılığı, genişliği, türleri, bir adım ve boyutuna çeviren bir tip kurtarma geçitini oluşturun.
  • DWARF 5 okuyucuyu yaz .debug_info- Evet ..debug_abbrev- Evet ..debug_str_offsetsve.debug_addrYer değiştirilebilir bir nesneyi kontrol ederek llvm-dwarfdump- Evet .
  • Geri alınan düzenle DWARF düzenle karşılaştırın ve her farkı eksik kanıt, birleşik erişim veya kanıtlanamayan bir tür olarak adlandırın.
  • Bir Itanium C ++ vtable, tipinfo ve yer değiştirme isimlerini okuyun ve bir yuvaya sanal bir çağrı çözün.

Sorun

  • Sen topladın .account.c- Hayır .-gBir ajanı ne diye sordu.bumpAjan nesneyi Ghidra 12.1.4'e gönderdi ve geri aldı:
c
void bump(long param_1,int param_2)
{
  *(int *)(param_1 + 4) = param_2 + *(int *)(param_1 + 4);
  return;
}

Aynı kaynakla oluşturulmuş .-gAynı dekompilerden verilmiş:

c
int bump(account *a,int by)
{
  a->balance = by + a->balance;
  return a->balance;
}

Bu nedenle, bu tabloyla ilgili olarak, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir dizi metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, bir metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metin, metinintAdı:balanceBu olmadan , dekompiler sadece 8 byt genişliğinde bir şey geldiğini bilir .%rdive 4 byte'de +4Okuduk ve yazıldılar.

Bu tabloda her şeyin kaynağı vardır.addl 0x4(%rax), %ecxGenişlik 4 ından geliyor .lİsim bir DW_TAG_memberGiriş .debug_infoBu ders iki yarı oluşturur: talimatların kanıtladığı şeyi geri alan bir geçiş ve kompiliörün kaydettiği şeyi çözen bir okuyucu.

Üyelik Erişimi Deplaşması

Intel SDM Cild 1, bölüm 3.7.5, etkin adresin olarak tanımlandığını belirtir.Offset = Base + (Index * Scale) + Displacement, 1, 2, 4 veya 8'lik bir ölçekle ve 8, 16 veya 32 bitlik bir yer değiştirme ile.RIP + Displacement. Strukt üye erişiminde, indekssiz ilk form kullanılır: temel kayıt, nesnenin adresini ve yer değiştirme üye sıfırını içerir. Bir dizide erişim indeks terimini ekler ve ölçek veya ayrı bir katılımcı eleman boyutunu taşır.

Al .bump- ...-O0- Listeden .llvm-objdump -d -rBu da şöyle:

output
       4: 48 89 7d f8                  	movq	%rdi, -0x8(%rbp)
       e: 48 8b 45 f8                  	movq	-0x8(%rbp), %rax
      12: 03 48 04                     	addl	0x4(%rax), %ecx
      15: 89 48 04                     	movl	%ecx, 0x4(%rax)

Çözümleme03 48 04Dersin kuralları ile 33.03- Evet .ADD r32, r/m32ModRM 48- Evet .01 001 000- Evet .mod = 018 bitlik bir yer değiştirme ile bir hafıza operandı anlamına gelir. reg = 001- Evet .%ecx- Evet .r/m = 000- Evet .%rax- Deplacement byte 04- Kural 4 byte okur .%rax + 4ve onları %ecx- Ne ?lİleği llvm-objdumpBaskılar operand boyutunda, bu yüzden alanın genişliği 4 byte.%raxÇizgilik boşluğundan geldi .-0x8(%rbp), ve bu boşluk aldı .%rdi, Sistem V çağrı kuralı altında ilk tam sayı argümanı. Üç gerçek aşağıda: ilk parametresi bir işaretçi, işaret ettiği nesne 4 byet bir alanı vardır ofset 4, ve bumpO alanı okuyor ve yazıyor.

Bu baytlarda hiçbir şey söylemiyor .int- Evet .balanceveyastruct accountHiçbir şey nesnenin ne kadar büyük olduğunu söylemez.bump- Evet .

Sistem V düzen kuralları

x86-64 psABI, bölüm 3.1.2, toplamalar için üç kural verir. "Yönemler ve sendikalar en sıkı bir şekilde uyumlu bileşenlerinin hizalanmasını varsayırlar. Her üye uygun hizalanma ile en düşük mevcut ofset'e atılır. Her nesnenin boyutu her zaman nesnenin hizalanmasının katııdır". Aynı belgenin 3.1 Şekili skalar boyutları ve hizalanmaları verir: char1 ve 1'i,short2 ve 2, int4 ve 4'e.double8 ve 8, herhangi bir işaretçi 8 ve 8.

Kurallar, yapılara uygulanmalıdır.account.c- ...

c
struct account {
    char kind;
    int balance;
    short code;
    double rate;
    const char *label;
};
MemberSizeAlignmentLowest offset that fitsPadding before
kind1100
balance4443 (bytes 1 to 3)
code2280
rate88166 (bytes 10 to 15)
label88240

Son üye 32'de sona erer. En sıkı düzeltme 8, 32'nin de 8'in katı olması, bu nedenle boyutu 32'dir.

Üyelerin sırası büyüklüğü belirler.double, pointer, int, short, char0'u, 8'i, 16'u, 20'i, 22'i ve 23'e kadar döngülmüş olan 23'e kadar tamamlanır. sysv_layout()İçeridecode/main.pyPython'un üç kuralını uyguladığında her iki sonuç da elde edilir.ctypesmodül, host kompozisyonunun bir kuralı ile aynı kuralları uyguluyor ve ctypes.sizeof- Evet .ctypes.alignment, ve .offsetHer alanın 32, 8 ve 0, 4, 8, 16, 24Bu makineyi oluşturduğunuzda programın kendisi üçüncü kopyayı basıyor:

output
sizeof 32 align 8
kind 0 balance 4 code 8 rate 16 label 24
sum 315 tag -3 projected 318.75 label_length 7

Bu yerel yapı, arm64'dir. Arm AAPCS64 bölüm 5.10.1'de aynı toplam kuralları belirtir ve Apple'ın arm64 belgesi bu beş skalar boyutunu korur, bu nedenle rakamlar iki hedefte uyumlu olur.-target x86_64-unknown-linux-gnuBöylece ders 33'ten ELF okuyucu ve aşağıdaki DWARF okuyucu bunları üzerinde çalışacak.

Yapıların Geri kalanını Elden Oku

bumpDiğer dört işlev account.cDiğerleri de farklı bir talimat formunu gösterir.account-x86_64-O0-g.objdump.txt- Evet .

sum_balancesStruktörün bir diziyi indeksize eder:

output
      51: 48 8b 45 f8                  	movq	-0x8(%rbp), %rax
      55: 48 63 4d ec                  	movslq	-0x14(%rbp), %rcx
      59: 48 c1 e1 05                  	shlq	$0x5, %rcx
      5d: 48 01 c8                     	addq	%rcx, %rax
      60: 8b 40 04                     	movl	0x4(%rax), %eax

%rax- Evet .list- Evet .%rcx- Evet .i64 bitlik bir işaretle uzanmış ve shlq $0x532 çarpı çarpı.addq- Evet .%rax- Evet .list + 32 * i, ve yük 4 byet olarak öğenin 4 ' ün tersine okur iBu nesnede, yapı boyutunun bir sayı olarak görünen tek yer var.0x49- ...jmp 0x49- ...0x72- Evet .

tagİki dar alanı okuyor:

output
      8c: 0f be 00                     	movsbl	(%rax), %eax
      98: 0f bf 48 08                  	movswl	0x8(%rax), %ecx

movsbl0'da bir byte yükler ve onu işaretle uzatır, bu yüzden 0'daki alan imzalı 1 byte tam bir sayıdır. movswl8. ofset'te iki byte yüklerken, işaret uzantısı ile, 8. alanın imzalanan 2 byte tam bir sayı olduğu ortaya çıkar.-O1İlk erişim cmpb $0x6c, (%rdi), yine de 0'da 1 byte diyor ve işaret hakkında hiçbir şey söylemiyor.

projectedBir kayganı okuyor:

output
      cc: f2 0f 2a 40 04               	cvtsi2sdl	0x4(%rax), %xmm0
      d5: f2 0f 59 40 10               	mulsd	0x10(%rax), %xmm0

cvtsi2sdl32 bitlik imzalanan bir tam sayıyı bellekten çiftine dönüştürür. Bu da ofset 4'ün imzalanan 4 byet tam sayıyı taşıdığını doğruluyor. mulsdhafızadan iki katına çarpır, bu yüzden 16'nın 8 baytlı bir akış noktası değeri var.

label_lengthbir işaretçi okuyor ve sonra takip ediyor:

output
      f3: 48 8b 40 18                  	movq	0x18(%rax), %rax
      f7: 48 63 4d f4                  	movslq	-0xc(%rbp), %rcx
      fb: 80 3c 08 00                  	cmpb	$0x0, (%rax,%rcx)
  • Evet .movqBu 8 byte bir bütün sayıdır.cmpbBir adres olarak kullanılan bir değer bir işaretçi.cmpbindekste 1 byte okuyor %rcxBu yüzden de-O1işaretçi ileriye doğru leaq 0x1(%rcx), %rcxBu da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da bir yandan da da da bir yandan da bir yandan da da da bir yandan da da bir yandan da bir yandan da da bir da bir da bir da bir da bir da bir da bir da bir da bir da bir da bir da bir da da da da da bir da bir da bir da bir da da da bir da bir da bir da

Beş fonksiyonu bir araya getirirsek yapı { i8 at 0, i32 at 4, i16 at 8, f64 at 16, pointer at 24 }1 ila 3 ve 10 ila 15 arasındaki boşluklar, psABI kurallarının öngördüğü dolgulama şeklidir.const char *, 0 ' da imzalanan baytın açıklanmış türü , kaynak tarafından yazılmıştır char, ve beş fonksiyonun aynı tipte olduğunu.main, ki bir çerçeve nesnesini tüm beşine geçirir.-O0Çağrı siteleri bunu görülebilir hale getirir: leaq -0x70(%rbp), %rdiArdından addq $0x20, %rdiDaha öncecallq bumpveaddq $0x40, %rdiDaha öncecallq tag- 0'luk oranı.0x20ve0x40Bir dizi üç unsur ve memcpy0x60Bu, 32'nin üç elementini oluşturan 96 byt'tır.

Geçit

trace_function()İçeridecode/main.pyBir tutıcı 64 bitlik bir kayıt veya bir çerçeve boşluğu gibi -0x8(%rbp)Her sahibin üç değerden biri vardır.Pointerbir adımın bir adımın bir bilinmeyen katı sayısı eklendiğini kaydettiği bir kök artı sabit bir sıfır artı bir adımlar kümesi.IndexBilinmeyen bir değerin tam bir sayısıdır.

Devlet , altı Sistem V argüman kayıtlarının olması ile başlar .Pointer("param0", 0)- Evet .Pointer("param5", 0)O zaman her talimat bir kuralı uyguluyor:

  • A.movq64 bitlik bir kayıt ve çerçeve boşluğu arasındaki değer kopyalanır. 32 bitlik veya daha dar bir kayıt kayıt bir kayıt yapar Index1 ölçeği ile.
  • A.leaqBir işaretleme tabanı ile bir işaretleme oluşturur ve bir indeks kaydı ile ekler scale * index_scale- Yapacak adımlar.leaqKimin tabanı %rbpveya %rspBir çerçeve nesnesinin adını verir, bu nasıl olur?mainGeçitlerrows- Evet .
  • shlq $nBir Indexölçeğini çarpır 2^nveimulq $kçarpı k- Evet .
  • addqBir işaretçi ve bir gösterge göstergeyi tutar ve gösterge ölçeğini adımlara ekler. addq $kBir işaretçiye karşı çıkışını hareket ettirir ve bu kayıtların bir artışı olarak da kaydedilir.
  • Bir çağrı, her aramacı kaydedilen kayıtları bilinmez hale getirir ve işaretleri tutan argüman kayıtları bir arama sitesi olarak kaydedilir.
  • Bas kayıtları bir işaretçiyi taşıyan her hafıza operandı bir Accessİzleyenin kökü ve sıfırı, genişliği ve türü ile mnemonik ve bir depo bayrağı.

Genişlik ve tür sadece mnemonikten gelir.access_width()haritalar b- Evet .w- Evet .lveq1, 2, 4 ve 8 bayt için sufişler, movsblve movswlİmza edilen dar yüklere,movzblİmza edilmemiş olanlara,sdve ss8 byet ve 4 byet yüzenlere verilen skalar SSE talimatları, cvtsi2sdlİmzalanmış 4 bayt tam sayı kaynağına ve 16 bayt movapsBir vektöre aile. leaqve nopFormular erişim değildir.

python
if memory.base in FRAME_REGISTERS:
    return Pointer(f"frame({memory.base}{format_signed(memory.displacement) if memory.displacement else ''})", 0)
base = env.get(memory.base)
if not isinstance(base, Pointer):
    return Unknown
strides = set(base.strides)
if memory.index is not None:
    index_value = env.get(memory.index)
    strides.add((index_value.scale if isinstance(index_value, Index) else 1) * memory.scale)
return Pointer(base.root, base.offset + memory.displacement, frozenset(strides), base.origin)

Bir işaretçi aracılığıyla 8 byte yüklenmesi, köken adı alanı oluşturan yeni bir işaretçi üretir, örneğin param0->0x18Bu değer daha sonra bir temel olarak kullanıldığında veya leaqBu kural, "8 byte"den "pointer"e çeviren 24'i karşılaştırır.

Dört çeşit adım kanıtı

infer_layout()Her tanık fonksiyonunun erişimlerini birleştirir ve her bir adımın ürettiği talimat ile birlikte dört kaynağından bir araya getirir.

KindWhere it comes fromBuild that shows it
scalean Index with scale above 1 reached a pointer, from shlq $0x5 or imulq-O0, shlq $0x5, %rcx at 0x59
loop-stepa 64-bit increment of the base or index register inside a loop that also contains the access-O1, addq $0x20, %rdx at 0x24
offset-deltasame-width accesses through one base register inside one loop, at offsets a constant apart-O2, eight loads 32 apart
call-sitethe offsets at which one frame object is passed to the witness functions-O0, main passes rows, rows+0x20, rows+0x40

Bir döngü geriye döner .jmpBu kural, addl $0x1, %eaxBu ilerliyor.i- ...-O0, çünkü 32 bit bir eklemedir ve erişim geçmediği için %eaxSon adım, bulunduğu her değerin en büyük ortak bölücüdür.

-O2'deki vektörlü döngü

  • Evet .-O2Klang vektörler sum_balances- Çubuk vücudu .0x50- ...0xaaBir geçit için sekiz element okuyor:
output
      3b: 48 8d 87 e4 00 00 00         	leaq	0xe4(%rdi), %rax
      50: 66 0f 6e 50 80               	movd	-0x80(%rax), %xmm2
      55: 66 0f 6e 98 60 ff ff ff      	movd	-0xa0(%rax), %xmm3
      61: 66 0f 6e 90 40 ff ff ff      	movd	-0xc0(%rax), %xmm2
      69: 66 0f 6e a0 20 ff ff ff      	movd	-0xe0(%rax), %xmm4
      7d: 66 0f 6e 10                  	movd	(%rax), %xmm2
      81: 66 0f 6e 58 e0               	movd	-0x20(%rax), %xmm3
      8a: 66 0f 6e 50 c0               	movd	-0x40(%rax), %xmm2
      8f: 66 0f 6e 60 a0               	movd	-0x60(%rax), %xmm4
      a0: 48 05 00 01 00 00            	addq	$0x100, %rax
      aa: 75 a4                        	jne	0x50 <sum_balances+0x40>

%raxBaşlıyor .list + 0xe4Sekiz yer değiştirme yükleri karıştırmalara yerleştirir .0x04, 0x24, 0x44, 0x64, 0x84, 0xa4, 0xc4, 0xe4-list, ki 4, 36, 68, 100, 132, 164, 196, 228- Artış 0x100Bu sayede, bir geçit, görüldüğü gibi, 8 alan ve en az 232 bytelik bir yapı rapor eder.

fold_unrolled()Bir döngü içinde, aynı genişliğe sahip erişimleri bir baz kayıtçası üzerinden alın.dEğer döngü adımları k * dVe tam olarak var.kAyrılıklı sıyrılar, döngü çözüldü.kZamanlar ve her erişim aynı eleman erişimini ofset olarak (offset - lowest) mod d- İşte .256 = 8 * 328 kargoyla kargoya 4'e katılır ve adımlar kaydedilmektedir.offset-delta 32- Evet .unrolled 32veloop-step 256- Skalare kalıntı döngüsü0xe0ekliyor scale 32-shlq $0x5, %rdxve loop-step 32-addq $0x20, %rdxBeş değerin en büyük ortak bölücü 32'dir.

Şekilde katlanmayı kapatan bir düğme var.-O2Bu durum, bu halka olmadan yer değiştirme güvenen bir okuyucu tarafından görülen bir durumdur.

DWARF 5 Bytes'ten

  • Evet .-gyapılandırmaaccount.cSekiz tane defekt bölümü var..debug_info493 byte..debug_abbrev179, .debug_str230, .debug_str_offsets124, .debug_addr112, .debug_line312, .debug_line_str12, ve .debug_frame264. DWARF 5 standart listelerinin kullanılması .debug_str_offsets- Evet ..debug_addrve.debug_line_str5. versiyonda yeni olarak.code/main.pyİlk beş tane lazım.

Birim başlığı

Standartın 7.5.1.1 bölümünde, toplam birim başlığı verilmiştir: unit_length- Evet .version- Evet .unit_type- Evet .address_sizevedebug_abbrev_offsetİlk 12 byte ..debug_infoBunlar:

output
e9 01 00 00   unit_length = 0x1e9 = 489
05 00         version = 5
01            unit_type = DW_UT_compile
08            address_size = 8
00 00 00 00   debug_abbrev_offset = 0
  • Evet .unit_typeBu sayede, bir sonraki birim 4 + 489 = 493Bölümün sonunda.llvm-dwarfdump --debug-infoAynı beş değerleri yazdırır Compile Unit:İlk test bu çizgiyi inceliyor ve karşılaştırıyor.

Kısacalar

Bölüm 2.1'de, her defuggerleme bilgisi girişinin "bir tanımlama etiketinden ve bir dizi özelliğinden oluştuğu" belirtilmektedir..debug_abbrevBu nesne 14 açıklamada bulunur. Burada iki önemli konu vardır:

output
[12] DW_TAG_structure_type  DW_CHILDREN_yes
     DW_AT_name              DW_FORM_strx1
     DW_AT_byte_size         DW_FORM_data1
     DW_AT_decl_file         DW_FORM_data1
     DW_AT_decl_line         DW_FORM_data1
[13] DW_TAG_member           DW_CHILDREN_no
     DW_AT_name              DW_FORM_strx1
     DW_AT_type              DW_FORM_ref4
     DW_AT_decl_file         DW_FORM_data1
     DW_AT_decl_line         DW_FORM_data1
     DW_AT_data_member_location  DW_FORM_data1

parse_abbreviations()ULEB128 kodu, ULEB128 etiket, bir çocuk bayt, sonra bir 0, 07.5.6 bölümünde form kodlamaları bulunmaktadır: data11 byte.ref4birim ile ilişkili 4 baytlı bir sıfırlama. strx1dizileri karşılaştırma tablosuna 1 baytlı bir indeks. sec_offsetve data44 byte.addrxadres tablosuna ULEB128 indeksi olarak yerleştirilmiştir. exprlocULEB128 uzunluğu ve bu çok bayt, ve flag_presentHiç bayt yok.

Balanç üyesini el ile çöz

için yapı girişaccount- Ofset'ten başlıyor.0x195Baytlarla 0c 15 20 00 03Kısaca 12'e ait bir kod, yapı.DW_AT_nameİndeks dizilisi 0x15- Evet .DW_AT_byte_size- Evet .0x20= 32,DW_AT_decl_file0 ve DW_AT_decl_line3'ün çizgisi.struct account {Kaynağı.

İkinci üye girişleri 0x1a3- Evet .0d 10 88 01 00 00 00 05 04- ...

  1. 0d13 kısaltması, bir üye.
  2. 10- Evet .DW_AT_name- Evet .strx1: string index 16.
  3. 88 01 00 00- Evet .DW_AT_type- Evet .ref4: karşılığı 0x188Birim başlangıcından itibaren, yani DW_TAG_base_typeAdı:int- Evet .
  4. 00- Evet .DW_AT_decl_fileve 05- Evet .DW_AT_decl_line: 5 satır account.c- Evet .
  5. 04- Evet .DW_AT_data_member_location: 4.

Bölüm 5.7.6 'da bir üye girişinin "ya DW_AT_data_member_location özelliğine veya DW_AT_data_bit_offset özelliğine sahip olabileceğini" ve tam bir sayı sabitinin "aşıyan bir varlıktan itibaren baytlarda karşılaştırıldığını" belirtmektedir. Bu bayt, addl 0x4(%rax), %ecxvecompare_layouts()Bu iki şeyi bir kenara koyan fonksiyon.

İpi ve adresler iki tabloda geçer

İpiş indeks 16 bir sıfırlama değil .debug_strOkuyucu alır .DW_AT_str_offsets_base8 olan birim girişinden 4 bayt girişini okur 8 + 4 * 16İçeride.debug_str_offsetsBu giriş , "balance"İçeride.debug_strAynı indirektlik adreslere de geçerlidir.sum_balancesBaytlarla başlar 07 07: kısaltma 7, bir alt program, sonra DW_AT_low_pc- Evet .addrxindeks 7. 8 baytlı giriş 8 + 8 * 7İçeride.debug_addr- Evet .0x30, fonksiyonun adresi .textBu tabloda ilk altı giriş, altı satırlı yazılardaki adreslerdir.

Yer değiştirilebilir bir nesnedeki hiçbir tablo son değerlerini tutmaz..debug_str_offsetsDosyada sıfırdır ve .rela.debug_str_offsets29'u tutmaktadır.R_X86_64_32.debug_strEk olarak gerçek tazminat ile..debug_addr13'ü var.R_X86_64_64.textve .rodata.str1.1- Evet ..debug_infoDört farklı yer değiştirme sistemi vardır: kısaltma ofset,DW_AT_str_offsets_base- Evet ..debug_str_offsets+0x8- Evet .DW_AT_stmt_listveDW_AT_addr_base- Evet ..debug_addr+0x8- Evet .ElfObject.relocated()uygulanır .S + AOkur bir bölüm analizini yapmadan önce 32 bit ve 64 bit türleri için. Bir bölüm simgesi bir nesne dosyasında 0 değerine sahiptir, bu nedenle alan eklemeyi alır. llvm-dwarfdumpaynı çözünürlükte, bu yüzden çıkış her çözünürlükte isim ve adresleri gösterir.

Tipler, fonksiyonlar ve yerler

DwarfInfo.type_name()Bu da ...DW_AT_typeİpuçlar.labelüye noktaları bir DW_TAG_pointer_type, bir DW_TAG_const_type, bu da charBas tip, bu yüzden isim const char *- Evet .type_size()DevamıDW_AT_byte_sizeTemel türler ve yapılarda, bir işaretçi için 8 ve bir dizi için element boyutunun sayısını çarpı. type_kind()DW_AT_encodingÜst tipten intbir işaretle, veyafloat, ve için bir işaretçi tipipointer, bu da karşılaştırma kullanan kelime birikimi.

DwarfInfo.functions()Altı okur.DW_TAG_subprogramGirişler.bump0x0- ...0x21, yani DW_AT_low_pcartı DW_AT_high_pcUzunluğu. Çerçeve tabanı DW_OP_reg6 RBP, ve parametre akonum ifadesini içerir 91 78- Evet .DW_OP_fbregSLEB128 değeri ile 0x78Bu da çerçeve boşluğu.-0x8(%rbp)listelenmenin depolanması%rdiAdresinde0x4Debug bilgisi ve talimatlar aynı boşluğu iki taraftan açıklar.

İki Yöntemin Karşılaştırılması

compare_layouts()DWARF üyelerini yürütür ve aynı sıyrıtındaki çıkarılan bir alanı arar.no-evidenceFarklı boyutlu bir alansize-mismatchAlanı hiç geri alınmamış bir işaretçi üyesipointer-unproven. Anıtlamalarda tam sayı aritmetik kullanıldığı bir float gibi, aynı fikirde olmayan bir tür, kind-mismatchÜyelik veya yastık içinden başlayan yerleşik alanlar unexpectedBoyut adımları karşılaştırır .DW_AT_byte_size- Evet .

Üç yapı için numaralar, python3 code/main.py- ...

BuildAccesses through the first parameterFieldsStride evidenceMembers matchedSize
-O0115scale 32, call-site 32, call-site 645 of 532, match
-O195loop-step 325 of 532, match
-O2175 after folding, 12 beforeoffset-delta 32, unrolled 32, loop-step 256, scale 32, loop-step 325 of 532, match

Sonuçlanan boşluklar her yapıdaki 1 ila 3 ve 10 ila 15 bytlerdir ve bunlar tam olarak DWARF düzeninin doldurma bytleri.natural_alignment_ok()Kayıtlar.

İşlevleri birbiriyle ekle ve resim değişir.bumpTek başına düzen 4'ün karşılaştırmasında bir alan, boyut bilinmemektedir ve alt sınır 8'dir. sum_balancesadımını ekler.tag0 ve 8 oranlarını ekler. projected16'da yüzen ekliyor.label_length24'e işaretçi ekler ve işaretçi olduğunu kanıtlar. main-O0Ve hiçbir şey eklemez.-O1ve -O2Bu sayede her yapılandırma için bu sırayı geçiyor.

Üç şey ulaşılmaz.İsimler talimatlarda bulunmuyor.const- Bu talimatlarda bulunmuyor.labelsadece "elementler 1 byte ayrı" leaq 0x1(%rcx), %rcx ile uyumlu olan string döngüsündecharve ileunsigned charve _Bool- Ne ?-O10'da byte işaretinin bilinmemesi, çünkü cmpb $0x6c, (%rdi)- Uzatmadan karşılaştırmalar yapılıyor.int8Orada vei8- ...-O0, nerede movsblBu gerçekler ders 35 kayıtları bilinmeyen olarak.

C++ nesneleri

shapes.cpptanımlar ShapeSanal bir yıkıcı, saf bir sanal area(), ve sanal bir name()veRect, Shapeve iki ekliyor.intItanium C++ ABI, clang'ın x86-64 Linux'ta bunları nasıl düzenlediğini yönetir.

Bozuk isimler

ABI'nin 5.1.2 bölümünde "Bir isim, öntanımla bozulur" der._ZBu nesne 19 simgeye sahip._ZNK4Rect4areaEvBu da şöyle:_ZO zaman ...NYatağındaki isim için,Kconst üyesi işlevi için, 4Rectve 4areauzunlukla belirlenmiş kaynak isimleri olarak, EYatağındaki isim kapatmak için vevboş bir parametrelist için. llvm-cxxfiltParmak iziRect::area() const- Evet ._Z8describeRK5Shapei- Evet .describe(Shape const&, int)- Evet .Rreferans olarak kullanılır.K- sabit.5Shapesınıfı.i- Evet .int5.1.4 bölümdeki özel isimler _ZTVbir masa için,_ZTItipinfo için ve _ZTSTypeinfo isimleri dizisi için.C1- Evet .C2- Evet .D0- Evet .D1veD2- Evet ._ZN4RectD0Evve _ZN4RectD2Evİkisi de basılı .Rect::~Rect(): silme yıkıcısı ve temel nesne yıkıcısı bir kaynak adı paylaşırlar.

Demanglerİçeridecode/main.pyBu alt kümeni ve 5.1.5.2 bölümünün yapı tipi kodlarını kapsar.S_5.1.10 bölümünün yerine getirilmesi. Test tüm 19 isimle çalıştırılır ve yakalananlarla karşılaştırılır.llvm-cxxfilt --no-strip-underscoreoutput. macOS'ta bayrak önemli, araç varsayılan bir önde gelen altını çıkarır ve ardından tanımamaktadır Z8describe...- Evet .

Yer değiştirmelerinden kaynaklanan

ABI'nin 2.5.2 bölümünde, sanal bir tabloun bileşenleri sırayla listelenir: sanal çağrı sıfırlamaları, sanal temel sıfırlamaları, üstteki sıfırlama, tipinfo işaretçisi ve ardından sanal fonksiyon işaretçileri. Adres noktası, bir nesnenin vptr değerinin, ilk fonksiyon işaretçisinin adresidir (2.6.2 bölüm). RectSanal tabanı yok, bu yüzden tablo üst, tipinfo ve fonksiyonlara karşılaştırılmıştır.

Simge ._ZTV4RectBu, 0x30 byte, 6 8-byte boşluk..rela.data.rel.ro._ZTV4Rect- ...

output
0000000000000008 R_X86_64_64              _ZTI4Rect
0000000000000010 R_X86_64_64              _ZN4RectD2Ev
0000000000000018 R_X86_64_64              _ZN4RectD0Ev
0000000000000020 R_X86_64_64              _ZNK4Rect4areaEv
0000000000000028 R_X86_64_64              _ZNK4Rect4nameEv

Slot 0, sıfırla yukarıya kadar sıfırlanır ve yer değiştirilmeye ihtiyaç duymaz. Slot 1 tipinfo.+16Oradan, 0'luk slot tam nesne yıkıcısı, 1'lik slot silme yıkıcısı, 2'lik slot.area, 3. bölümname- Evet .read_vtable()simge boyutunu, aralığında yer değiştirmeleri ve sıfırı sıfırdan okur.ShapeMasanın şekli aynı .__cxa_pure_virtual2. slot'da, saf bir sanal çağrıya ulaşan çalıştırma süresi fonksiyonu.

RTTI

Bölüm 2.9.4'te std::type_infobir vptr olarak, mangled tip adına bir işaretçi ile takip edilir ve elde edilen sınıfları listeler. _ZTI4RectÜç yer değiştirdi: _ZTVN10__cxxabiv120__si_class_type_infoE+0x10- Evet ._ZTS4Rectve_ZTI5ShapeBirincisi , Vtable ' deki__si_class_type_info, ABI'nin sıfır sıfırında tek bir kamu-virtual olmayan tabanlı bir tip için kullandığı sınıf ve +0x10Bu vtable'nin adres noktası.4Rect, ki bu da kırık tip adı ve name()Bir .type_infoÜçüncü, taban._ZTI5Shapekullanımı __class_type_infoVe bir temel işaretçisi yok.read_typeinfo()Bu üç gerçeği geri verir.

Sanal çağrı

describe- ...-O0Bir sanal çağrı yapar:

output
       f: 48 8b 7d f8                  	movq	-0x8(%rbp), %rdi
      13: 48 8b 07                     	movq	(%rdi), %rax
      16: ff 50 10                     	callq	*0x10(%rax)

İlk .movqİkinci birinde, nesneyi vptr olarak adlandırılan 0'da 8 byte okuyor, çünkü ABI onu ilk olarak sanal fonksiyonlu bir sınıfa yerleştirir.callqGeçer.0x10VPTR'den geçti ve0x10 / 82. bölüm.find_virtual_calls()İhtiyacımız olan iki adayla aynı şekilde konuşur ve raporlar verir: Rect::area() const-_ZTV4Rectve __cxa_pure_virtual-_ZTV5ShapeHangisi çalışacak, nesneye bağlıdır, bu yüzden arama dolaylı.

DWARF aynı bölgeyi kaydeder.DW_TAG_subprogram için girişlerareaHer iki sınıf da taşıyıcıdır.DW_AT_vtable_elem_location (DW_OP_constu 0x2)- Evet .name3 numaralı slot taşıyor, destruktorlar 0 numaralı slot taşıyor.Rect- birDW_TAG_structure_type16 bytelik bir DW_TAG_inheritance için girişShape0 ve üyeleri w8 ve hSaat 12.Shape8 byte bir yapay üye ile _vptr$Shapeİki bağımsız türeç 2 bölümü verir area: yer değiştirme tablosu ve hatalama girişleri.

  • Evet .-O1nesne hiçbir şekilde vtable'a sahip değil.mainyapıları RectYerel olarak, böylece derleyici çözüldü r.name()ve describe(r, 2)Bu yüzden tablo yayınlanmıyor. describeHala içerir movq (%rdi), %raxve callq *0x10(%rax), çünkü parametri herhangi bir olabilir .ShapeKayıp bir vtable bir nesne dosyası hakkında bir gerçek ve test test_the_optimised_object_keeps_the_call_pattern_but_drops_the_vtablesİki yarısını da kontrol eder.

Microsoft ABI'nin bu detayların her biriyle farklılık gösterir.?Ve çağrı konvansiyonunu kodlayacağız.void test(void)C++ olarak oluşturulmuştur.__cdecl- Evet .?test@@ZAXXZRTTI konumlandırıcısı vfptr[-1]bir _RTTICompleteObjectLocator, ve semboller ??_7bir vftable ve ??_R4Microsoft'un kendi belgeleri "kompilatör satıcıları arasında C++ isimlendirme standartları yoktur" diyor.

Araçlar Nasıl Yenilen Türleri Tanıtır

Aşağıdaki her satırda bir çıkış adı var . Bu makine üzerinde üretilmiş ve içeriye kaydedilmiş .code/fixtures/tools/Burada kurulmayan aletler için satırlar, belgeleri anlatır ve böyle söyler.

ToolVersion, licenceWhere types liveOn our fixtures
Ghidra12.1.4, 2026-09-21, Apache-2.0Data Type Manager with built-in, user-defined, and derived types; .gdt archives; types used by a program are copied into itWith DWARF: /DWARF/account.c/account size=32 align=8 and a->balance = by + a->balance;. Without: *(int *)(param_1 + 4) with long param_1, tag(char *param_1), and *(char **)(param_1 + 0x18)
IDA Pro9.4, 2026-07-13, commercial; IDA Free is non-commercial with a cloud decompiler for x86 onlyLocal Types window, .til type libraries, DWARF and PDB import into a dwarf or pdb folderNot installed. Documentation only
Binary Ninja6.0, 2026-09-03, commercial with a Free editionType editing, header import and export, type archives, debug info from DWARF and PDB, type libraries, platform typesNot installed. Documentation only
radare26.2.4, 2026-10-05, LGPLv3ts, tsc, afvdts and tsc account printed nothing for the relocatable object with bin.dbginfo=true; pdf shows mov dword [rax + 4], ecx with source line comments from DWARF
rizin0.9.1, 2026-06-29, LGPL corets, tsc, afvdtsc account printed struct account { char kind; int balance; short code; double rate; const char *label; }; from DWARF; the build without -g lists only its bundled header types
lldblldb-1703.0.236.21image lookup -tbyte-size = 32 and the full compiler_type text from the ELF object
gdbnot installed hereptype /o prints "the offsets and sizes of fields in a struct" with holes markedDocumentation only
pyelftools0.33, public domainPython API over .debug_infoA 43-line script prints the same five members and unit version 5
llvm-dwarfdumpApple LLVM 17.0.0--debug-info, --debug-abbrev, --debug-str-offsetsThe oracle for every reader test

Ghidra'nın DWARF olmadan çıkışı aynı iki kuralın çalışmasını gösterir.char * parametreye kadartagÇünkü işlev bir bayt ile karşılaştırılır ve char **Sahaya çıkmak için0x18Çünkü ...label_lengthyüklenmiş değerden ayrılır ve baytları karşılaştırır. Bu dersdeki geçiş aynı iki kuraldır: talimattan genişlik, işaretten işaret. Ghidra'nın dekompiler belgesinde, p-kod varnodlarının "her zaman onlarla ilişkili bir veri türüne sahip olmadığı" ve dekompilerin "sonunda yayım yoluyla resmi bir veri türü tahsis ettiği" belirtiliyor. "Konsant göstericileri yerleştir" seçeneği aynı yayılımı sabitlere uzattır. Ghidra 12.1 bu ders için kullanılan cihazlarda kullanılamayan bitfield recovery'i dekompilerle birlikte ekledi.

Ghidra'nın Veri Tipi Yöneticisi, IDA'nın Yerel Tipleri, Binary Ninja'nın Arşivleri ve Rizin'in tdBu sayede, tüm bu programlar, geri alınan düzenden struct'u yazıp, dekompiler yeniden gönderilmesini izleyebilirsiniz.

rea 6.5.0 Ghidra sağlayıcısı ile dekompiler metnini bir kayıt olarak gönderir. Ghidra satırındaki her şey ona uygulanır ve kayıt, tür isimlerini üreten kanıt olmadan taşıyor.python3 code/main.py inferAynı listeye girerek de bu kanıtı bulmuşsunuz.

Tip İflası Araştırmaları

Bu geçiş, bir tip çıkarma sisteminin kısıtlama-genreasyon yarısını, bir parametre ile elde edilen bir yapı ile sınırlı olarak gösterir.

  • TIE (Lee, Avgerinos, Brumley, NDSS 2011) tip yeniden yapılandırmasını kısıtlama üretimi olarak çerçeveledi ve ikili bir IR üzerinde çözme, muhafazakârlığı ve hassasiyeti ölçtü ve 87 temel programda ticari bir dekompilerle karşılaştırdı.
  • Retypd (Noonan, Loginov, Cok, PLDI 2016) alt türleme, polimorfizm ve rekürsiv türler ekledi ve gösterge yeniden yapılandırılması rapor edildi constGrammaTech'in adı altında açık kaynaklı bir uygulamada mevcuttur.
  • OSPREY (Zhang ve diğerleri, IEEE S&P 2021) her bellek konumunu rastgele bir değişken olarak değerlendirir ve en olası türleri çıkarır.
  • DIRTY (Chen ve diğerleri, USENIX Security 2022) ve ReSym (Xie ve diğerleri, CCS 2024) öğrenilmiş modellerle işlem sonrası dekompiler çıkışı ve ReSym, tam yapı düzenleri üzerinde 72,9% doğruluk raporları.
  • RecStruct (Chen ve diğerleri, USENIX Security 2026), akış-ansız sembolik yürütme ve yığın boşlukları üzerinde birlik-görme ile, bir dekompiler olmadan yuvalanmış structs kurtarır.

Bu dersin geçişinin atladığı ilk şey, yığın yapısı.-O1- Evet .main- Devam ediyor .rowsDüğme ve içe yazılmış kod üzerinde yazıyor .0x24(%rsp)- Evet .0x40(%rsp)- Evet .0x48(%rsp)- Evet .0x30(%rsp)ve0x38(%rsp)Bu modül 32 oranları 4, 0, 8, 16 ve 24'dir. Aynı yapı, ekmek için parametre yoktur.

Yapın

Demo çalıştır:

bash
cd phases/13-tools-and-protocols/41-recovering-data-and-types
python3 code/main.py
npx tsx code/main.ts

Çıktı bir JSON raporu beş parçalı. dwarfBirim başlığı, yapıları ve fonksiyonlarını içerir.-O0- Ne? - Ne?oraclespsABI kural düzenini içerir, ctypesdüzen, DWARF düzen, yerel çalıştırma ve agreeBayrak.buildserişimleri, çıkarılan düzen ve üç nesnenin her biri için karşılaştırmayı içerir. cxxİsimleri, her iki vtables, her iki tipinfo kayıtlarını, sanal çağrı ve DWARF yuvalarını içerir. toolsKaydedilen araç çıkışlarını listeler.

Beklenen şekil:

json
{
  "dwarf": {"unit": {"unitLength": 489, "version": 5, "unitType": "DW_UT_compile", "addressSize": 8, "abbrevOffset": 0}, "...": "..."},
  "oracles": {"agree": true, "psabiRules": {"size": 32, "align": 8, "...": "..."}, "...": "..."},
  "builds": {
    "O0": {"layout": {"stride": 32, "size": 32, "gaps": [1, 2, 3, 10, 11, 12, 13, 14, 15], "...": "..."}, "comparison": {"matches": 5, "members": 5, "...": "..."}},
    "O1": {"...": "..."},
    "O2": {"...": "..."}
  },
  "cxx": {"virtualCalls": [{"slot": 2, "candidates": {"Shape": "__cxa_pure_virtual", "Rect": "_ZNK4Rect4areaEv"}, "...": "..."}], "...": "..."}
}

Oku code/main.pyBu sırada:

  1. ElfObjectBölümleri, sembolleri ve yer değiştirmeleri okuyor ve relocated()uygulanır .S + ABir hata düzeltme bölümüne.
  2. parse_abbreviations()ve DwarfInfo._parse_unit()Başlığı, kısaltma tablosunu ve girişleri okuyun ve sonra çözün strxve addrxİki masa üzerinden.
  3. DwarfInfo.struct_layouts()ve functions()Girişleri StructLayoutve FunctionInfoKayıtlar, type_name()- Evet .type_size()vetype_kind()- Evet .
  4. parse_listing()- Evet .parse_memory()veaccess_width()Okuyun .llvm-objdumpMesaj.
  5. trace_function()- Abstrakt devlet makinesi vefold_unrolled()ve infer_layout()Girişleri bir düzenle dönüştürün.
  6. compare_layouts()Durum satırlarını oluşturur ve sysv_layout()ve ctypes_layout()Diğer iki peygamber.
  7. Demangler- Evet .read_vtable()- Evet .read_typeinfo()vefind_virtual_calls()C++ nesnesini kapsar.

Dört emir daha var.python3 code/main.py dwarf FILE.oDWARF 5'in yer değiştirilebilir nesnelerinin yapıları ve fonksiyonlarını yazdırır. python3 code/main.py infer LISTING.txt [FILE.o]Bir listeye geçiş yapar ve bir nesne ile DWARF'e karşı karşılaştırır. python3 code/main.py demangle NAME...ve python3 code/main.py vtable FILE.oC++'in yarısını kapsar.

Kullan

Kendin inşa ettiğin yeni bir nesne üzerine:

  1. Yakalamallvm-objdump -d -rBu, bir nesneyi bir kenara bırakıp, bir nesneyi bir kenara bırakır.
  2. Çık .python3 code/main.py inferBir işlev eksikse, parametri bir hafıza operandına asla ulaşmadı veya geçiş izlemeyen bir yol boyunca birine ulaştı.
  3. Her alanı erişim sayısıyla okuyun. Bir erişim bir tanık.
  4. - Devamı kanıtını oku.call-siteveya scaleGiriş güçlü.loop-stepDiğer bir türden bir giriş zayıfdır, çünkü bir yuvarlak bir döngü birkaç elementin adımını bildirir.unrolledGörünür, katılamayı elden kontrol et.
  5. Eğer-goluşturmak var, karşılaştırmayı çalıştırmak ve olmayan her satırı okumak match- A.no-evidenceSatır bir üye adını verir.unexpectedGeçit yerleştiremediği bir giriş için sıra isimleri.
  6. Düzenlemeyi araçınızın tip yöneticisine bir yapı olarak yazın ve hangi alanların, isimlerin ve türlerin tahmin olduğunu kaydetin.

Üç müjdeciyi erişime bırak.ctypes, ve DWARF yazdığınız bir düzenle ilgili anlaşmazlıklarda, bir paketli yapı, bir bit alanı veya farklı kurallar ile bir hedef bulmuşsunuz.

İnteraktif Laboratuvar

Laboratuvar A: Üye girişini çöz

  • Evet .codeDizin, açık Python:
bash
cd phases/13-tools-and-protocols/41-recovering-data-and-types/code
python3 -q

Çık:

python
from main import *
elf = load_object("account-x86_64-O0-g.o")
dwarf = DwarfInfo(elf)
dwarf.header()
elf.section(".debug_info").data[0x1a3:0x1ac].hex(" ")
dwarf.dies[0x1a3].attributes
dwarf.type_name(dwarf.type_of(dwarf.dies[0x1a3]))

Sözlüğü incelemeden önce dokuz bayt kağıt üzerinde 13 kısaltma ile çöz.elf.section(".debug_str_offsets").data[8:16].hex(), ve yer değiştirilmiş olan,elf.relocated(".debug_str_offsets")[8:16].hex(), ve farkı açıkla.

Laboratuvar B: bir fonksiyonu izle

python
listing = load_listing("account-x86_64-O0-g.objdump.txt")
trace = trace_function("label_length", listing["label_length"])
[(hex(a.address), a.root, a.offset, a.width, a.kind) for a in trace.accesses]
trace.pointer_uses
trace_function("sum_balances", listing["sum_balances"]).loops

İndirmeden önce, hangi erişimden, ofset 24'in bir işaretçi olduğunu kanıtladığını yazın.-O1listeler ve bulma leaq 0x1(%rcx), %rcxİçeridetrace.increments- Evet .

Laboratuvar C: vektörlü döngüyü katlayın

python
o2 = load_listing("account-x86_64-O2-g.objdump.txt")
trace = trace_function("sum_balances", o2["sum_balances"])
sorted({a.offset for a in trace.accesses})
folded, evidence = fold_unrolled(trace, trace.accesses)
sorted({a.offset for a in folded}), [(e.kind, e.value, e.text) for e in evidence]

O zaman koş .analyze_build("O2", fold=False)["comparison"]Ve sayın unexpectedDönüş kuralını değiştir, böylece döngü adımının tam olarak olması gerekir.k * d- Evet .kEn az 2 ve onaylayın ki -O1Bir giriş ve 32 adımla, yalnız kalır.

Laboratuvar D: tablo ve isimler

python
shapes = load_object("shapes-x86_64-O0-g.o")
read_vtable(shapes, "_ZTV4Rect")
read_typeinfo(shapes, "_ZTI4Rect")
demangle("_ZNK4Rect4areaEv"), demangle("_Z8describeRK5Shapei")
find_virtual_calls(load_listing("shapes-x86_64-O0-g.objdump.txt"), [read_vtable(shapes, "_ZTV5Shape"), read_vtable(shapes, "_ZTV4Rect")])

Çizgiyi hesapla callq *0x10(%rax)Kağıt üzerinde, sonra onaylayın.DwarfInfo(shapes).struct("Rect").virtual_methods- O zaman yüklen .shapes-x86_64-O1-g.oVe denemek için .read_vtable- Bu kitapta oku.ElfErrorSimgolu neden yok olduğunu açıklayın.

Pratik Laboratuvar

Düğüm yapılarını geri alın main- ...-O1- Evet .

Gereksinimler:

  • Uzaklaştırmatrace_function()Yani çerçeve boşluğu bölgesi bir kök olabilir.movapsDükkanlar dolsun0x0(%rsp)- ...0x5f(%rsp)-.data.rel.ro, 96 baytlı başlangıçlayıcıdır rows- Evet .
  • İçeride girişleri atfedin 0x24(%rsp)- Evet .0x40(%rsp)- Evet .0x48(%rsp)- Evet .0x30(%rsp)ve0x38(%rsp)Bu kök ve rapor onların modulo bir aday adım karşılaştırır.
  • 32 adımını döngüden çıkarın 0x120- ...0x12c, nerede %r144'te başlar ve ilerler.0x20- ... ...0x64, ve bu döngünün bağlandığını göster .0x643 element artı alan sıfırlaması.
  • Sonuçları DWARF düzenle karşılaştırın ve beş maçın içine girin ve hangi türlerin kanıtlanmamış olduğunu kaydetin.
  • Çerçeve kökü bir parametre atfedildiğinde başarısız olan bir test ekleyin.

Başarılı olmak demektir .python3 code/main.py infer- ...-O1listeler listeleri mainÇizgi kökü olan bir tanık olarak ve karşılaştırma beş eşleşme gösterir main- Yalnız.

Ders Artifakti

Bu ders de içerir .outputs/skill-recovering-data-and-types.md. Bir listeni ve seçmeli bir defag yapısını bir alan için kanıtlı bir yapı düzeni, kaynaklarıyla bir adım, DWARF ile karşılaştırma ve bilinmeyenlerin bir listesine dönüştürmek için kullanın.

Kontrol et

Demo ve Deterministik Suite'i çalıştır:

bash
cd phases/13-tools-and-protocols/41-recovering-data-and-types
python3 code/main.py
npx tsx code/main.ts
python3 -m unittest discover -s code/tests -v

Verifikasyon, şunu kanıtlamalıdır:

  • Birim başlığı, 14 kısaltma ve beş üyelik karşılığı llvm-dwarfdump
  • Adlar yer değiştirilenler üzerinden gelir..debug_str_offsetsMasanın ve birimin str_offsets_baseve addr_base8
  • Altı fonksiyon aralıkları taşır.DW_OP_reg6 RBPveDW_OP_fbregToplama gösterdiği yerler ve düşük adresleri listelenme fonksiyonuna eşittir başlıyor
  • olmadan bir nesne.debug_infoLEB128 dekodörleri ile birlikte 0x78-8 olarak
  • pyelftoolsve lldbOkuyucu ile aynı düzeni bas
  • psABI kuralları, ctypes, DWARF ve yerli çalıştırma karşılığı verir 0, 4, 8, 16, 24ve 32 boyutlu, ve yeniden düzenlenmiş yapı 24 byte.
  • listesi analizci 13 talimat okuyor bump, bağlayıcılar R_X86_64_PLT32 bump-0x4Telefonla görüşme için0x194, ve geriye atlamayı bulur .0x72
  • AT&T metni ve mnemonikten hafıza operandları, genişlikleri, türleri ve işaretleri çözünür
  • bump- ...-O0İzleyiciyi çerçeve boşluğundan geri okuyor ve 4'ün tersine üç kez girişi yapar.
  • Bu adımın sebebi shlq $0x5- ...-O0, addq $0x20, %rdx- ...-O1, ve sekiz yükten 256 adımla katlanmış olarak -O2
  • label_lengthGöstericini, referansı geri çevirerek, ofset 24'te göstericini kanıtlar.
  • main0'da bir çerçeve nesnesini geçiyor. 0x20ve0x40- ...-O0Ve sadece printf- ...-O1
  • Her yapı 5 üyenin 5'ine 32 boyutlu ve DWARF dolguya eşit boşluklarla eşittir.
  • -O232 byte ve boyutsuz yedi alan rapor oluştur
  • Demangler tüm 19'u yeniden üretiyor.llvm-cxxfiltipler
  • hem vtables hem de tipinfo kayıtları ve sanal çağrı.0x162 numaralı yuva'ya karar ver. DWARF kabul ediyor.
  • -O1C++ nesnesi çağrı kalıbını korur ve vtable yoktur
  • Ghidra, rizin ve radar2 fotoğrafları, DWARF ile yapı ve olmadan ham karşılaştırmalar gösteriyor.
  • İnteraktif rakam analizle elde edilen aynı verileri içerir.

Üretim Başarısızlık Modları

FailureWhat the weak tool reportsWhat the analysis must prove
Unrolled loopEight fields 32 bytes apart and a 232-byte structLoop step 256 equals 8 times the offset delta 32, so one field at offset 4
Stride read from one incrementsizeof 256 from addq $0x100The greatest common divisor of every stride source, with the scalar tail's addq $0x20
8-byte field called a pointervoid * at offset 24A later access uses the loaded value as a base, or the kind stays int64
Pointer called an integerlong at offset 24The dereference at 0xfb, recorded as pointer proof
Narrow comparechar with a signcmpb carries no sign; only movsbl or movzbl does
Five functions assumed to share a typeOne struct with no evidence of aliasingCall sites in main that pass one frame object, or an explicit analyst assertion
Strings read from .debug_str by indexGarbage names from a relocatable objectstr_offsets_base plus the relocated .debug_str_offsets entry
Addresses read as numberslow_pc of 0 for every functionaddrx through the relocated .debug_addr table
DWARF 4 objectA reader that misparses the headerVersion check on the second header field; 4 has no unit_type byte
Missing vtable"the class has no virtual functions"The -O1 object inlined every call; the -O0 object has the table and its relocations
Vtable slot read from the wrong baseOff-by-two slot numbersThe address point is 16 bytes past the symbol, after offset-to-top and typeinfo
Mangled name strippedZ8describeRK5Shapei left as is--no-strip-underscore on macOS, or a demangler that checks for _Z
Struct typed from one tool's guesschar *param_1 taken as the field typeThe width and the dereference, written as evidence, and the name marked as a guess

İşlem Kuralı

Bir girişten bir alan ve bir döngüden bir adım geri alın ve talimatı her birine bağlayın. Bir atışın ötesine güvenmeden önce, çözülmemiş döngüleri katlayın. DWARF'ı kısaltma ve yer değiştirilmiş tabloları üzerinden oku, hiçbir zaman bir dizilme bölümüne indeksleme yapmayın. Alanla alan karşılaştır ve her üyeyi kanıtsız, kanıtlanmamış her işaretçi ve her isim bilinmeyen olarak yaz. C++ nesnesinde, vtable'yi yer değiştirmelerinden ve çağradan boşluğu okuyun, sonra okuduğunuz boşluğu onaylamak için DWARF kullanın.

Daha Fazla Okumak

This free lesson is part of the AI Engineering from Scratch curriculum. Read the full explanation, run the lesson code, and verify the result in the interactive reader or from the repository source.

Browse the complete course catalog or open this lesson on GitHub.