Ohjelmistojen käänteinen suunnittelu ja binäärien analysoinnin perusteet · Oppitunti

Tietorakenteiden palauttamisen automatisointi

Kehittäkää komentojonoja monimutkaisten tietorakenteiden automaattiseen tunnistamiseen ja rekonstruointiin hämärretyistä binääreistä.

Oppitunti 2/412 vaihetta

Tietorakenteiden palauttamisen automatisointi on ilmainen Ohjelmistojen käänteinen suunnittelu ja binäärien analysoinnin perusteet-oppitunti CoddyKitissä. Tämä on oppitunti 2/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu Ohjelmistojen käänteinen suunnittelu ja binäärien analysoinnin perusteet-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Ohjelmistojen käänteinen suunnittelu ja binäärien analysoinnin perusteet-kurssilla on yhteensä 4 oppituntia.

Mitä tietorakenteet ovat?

Ohjelmoinnissa tietorakenne on tapa järjestää ja tallentaa tietoja tehokkaasti. Voitte ajatella sitä siististi järjestettynä arkistokaappina toisiinsa liittyville tiedoille.

Käänteisessä suunnittelussa käsittelemme usein käännettyjä ohjelmia, mikä tarkoittaa, että alkuperäinen lähdekoodi ei ole enää saatavilla. Tavoitteena on "nähdä" nämä piilotetut arkistokaapit raakadatan binäärimuodossa.

Tietojen palauttamisen merkitys

Tietorakenteiden palauttaminen on tärkeää ohjelman logiikan ymmärtämiseksi. Kun tiedätte, miten olio on järjestetty muistissa, voitte:

  • ymmärtää, miten eri tiedonosat liittyvät toisiinsa
  • tunnistaa ohjelman tärkeät muuttujat
  • paikantaa mahdolliset haavoittuvuudet helpommin

Se muuttaa tavukasan merkitykselliseksi tiedoksi!

Piilotettujen rakenteiden löytäminen

Kun ohjelma käännetään, kääntäjät poistavat usein virheenkorjaustiedot ja optimoivat koodia. Tämän vuoksi rakenteiden automaattinen tunnistaminen on vaikeaa, koska:

  • alkuperäiset nimet katoavat
  • kenttien järjestystä saatetaan muuttaa tai niiden väliin lisätä täytettä
  • monimutkaiset rakenteet voivat olla hajallaan

Se on kuin yrittäisi koota palapeliä ilman mallikuvaa tai reunapaloja!

Yksinkertaiset tyypit binääridatassa

Ennen monimutkaisten rakenteiden käsittelyä palautetaan mieleen, miltä perustietotyypit näyttävät raakatavuina. Rakenne on vain kokoelma näitä yksinkertaisempia tyyppejä.

Esimerkiksi kokonaisluku voi viedä 4 tavua ja merkki 1 tavun. Niiden järjestyksellä ja koolla on merkitystä!

import struct

# Simulate a small piece of binary data
binary_data = b'\x01\x00\x00\x00' + b'\x41' + b'\x02\x00\x00\x00'

print("Raw bytes:", binary_data)

# Interpret bytes 0-3 as a 32-bit integer (little-endian)
# '<I' means little-endian unsigned int
int_val = struct.unpack('<I', binary_data[0:4])[0]
print(f"Integer (offset 0): {int_val}")

# Interpret byte 4 as a character
char_val = chr(binary_data[4])
print(f"Character (offset 4): {char_val}")

# Interpret bytes 5-8 as another 32-bit integer
int_val2 = struct.unpack('<I', binary_data[5:9])[0]
print(f"Integer (offset 5): {int_val2}")

Mikä on 'struct'?

C:n kaltaisissa kielissä struct on käyttäjän määrittämä tietotyyppi, joka kokoaa toisiinsa liittyvät muuttujat yhdeksi kokonaisuudeksi. Kuvitelkaa "User"-struct, joka sisältää käyttäjän tunnisteen (kokonaisluku), nimen (merkkijono) ja iän (kokonaisluku).

Käännettynä tämä struct vie muistista yhtenäisen alueen, jossa jokainen kenttä sijaitsee tietyssä siirtymässä alueen alusta laskettuna.

Rakenteiden tunnistaminen manuaalisesti

Kun teette käänteistä suunnittelua manuaalisesti, etsitte esimerkiksi seuraavanlaisia vihjeitä:

  • Toistuvat käyttökuviot: Koodi lukee tai kirjoittaa aina kohdissa [reg + 0], [reg + 4] ja [reg + 8].
  • Funktioargumentit: Funktiolle välitetään suuri muistialue yhtenä argumenttina.
  • Osoittimet: Kenttä osoittaa toiseen tunnettuun rakenteeseen tai tietotyyppiin.

Nämä kuviot viittaavat rakenteiseen data-alueeseen.

Kuviomallien haun automatisointi

Rakenteiden etsiminen manuaalisesti on työlästä! Tässä skriptit ovat hyödyllisiä. Voimme kirjoittaa skriptejä, jotka etsivät binääridatasta automaattisesti yleisiä kuvioita, jotka saattavat viitata rakenteeseen.

Skripti voisi esimerkiksi etsiä kahta kokonaislukua, joita seuraa nollapäätteinen merkkijono. Tämä on hyvin yleinen yksinkertaisten olioiden kuvio.

def find_pattern(data_bytes: bytes, pattern_bytes: bytes):
    """Searches for a byte pattern within a larger byte string."""
    indices = []
    for i in range(len(data_bytes) - len(pattern_bytes) + 1):
        if data_bytes[i:i+len(pattern_bytes)] == pattern_bytes:
            indices.append(i)
    return indices

# Simulate a binary's data section
simulated_binary_data = (
    b'\xDE\xAD\xBE\xEF' +  # random bytes
    b'\x01\x00\x00\x00' +  # int 1 (little-endian)
    b'\x0A\x00\x00\x00' +  # int 10
    b'NAME\x00' +          # string "NAME"
    b'\x00\x00\x00\x00' +  # padding
    b'\x02\x00\x00\x00' +  # int 2
    b'\x0B\x00\x00\x00' +  # int 11
    b'ITEM\x00'            # string "ITEM"
)

# Define a pattern to search for: int(1), int(10), string("NAME")
pattern_to_find = (
    b'\x01\x00\x00\x00' +
    b'\x0A\x00\x00\x00' +
    b'NAME\x00'
)

found_at_offsets = find_pattern(simulated_binary_data, pattern_to_find)

if found_at_offsets:
    print(f"Pattern found at offsets: {found_at_offsets}")
else:
    print("Pattern not found.")

Ristiviitteet rakenteiden vihjeinä

Käänteisen suunnittelun työkaluissa ristiviite (xref) näyttää, missä tiettyä osoitetta tai dataa käytetään koodissa.

Jos monet funktiot käsittelevät johdonmukaisesti tietystä osoitteesta alkavaa dataa ja sen jälkeen kohtia +0x4, +0x8 ja +0xC, nämä ristiviitteet viittaavat vahvasti siihen, että kyseisessä muistipaikassa käsitellään tietorakennetta.

Skriptit voivat automatisoida näiden ristiviitteiden analysoinnin!

Tietorakenteiden määrittäminen skriptillä

Kun olette tunnistaneet mahdollisen tietorakenteen asettelun esimerkiksi kuvioiden tai ristiviitteiden avulla, skripti voi määrittää tämän rakenteen itse käänteisen suunnittelun työkalussa.

Tämä tarkoittaa, että työkalulle ilmoitetaan: "Tässä osoitteessa on rakenne nimeltä 'MyObject', jonka siirtymässä 0 on kokonaisluku 'ID' ja siirtymässä 4 merkkijono 'Name'."

Tämä tekee puretusta koodista paljon luettavampaa, sillä raakamuisteihin tehdyt viittaukset korvataan merkityksellisillä kenttänimillä!

import struct

# Reusing simulated_binary_data from previous example
simulated_binary_data = (
    b'\xDE\xAD\xBE\xEF' +  # random bytes
    b'\x01\x00\x00\x00' +  # int 1 (little-endian)
    b'\x0A\x00\x00\x00' +  # int 10
    b'NAME\x00' +          # string "NAME"
    b'\x00\x00\x00\x00' +  # padding
    b'\x02\x00\x00\x00' +  # int 2
    b'\x0B\x00\x00\x00' +  # int 11
    b'ITEM\x00'            # string "ITEM"
)

class ItemStruct:
    def __init__(self, data_bytes, start_offset):
        # We assume the struct starts at start_offset in data_bytes
        # Field 1: 4-byte integer (ID) at offset 0 from struct start
        self.item_id = struct.unpack('<I', data_bytes[start_offset:start_offset+4])[0]
        
        # Field 2: 4-byte integer (Quantity) at offset 4 from struct start
        self.quantity = struct.unpack('<I', data_bytes[start_offset+4:start_offset+8])[0]
        
        # Field 3: Null-terminated string (Name) at offset 8 from struct start
        name_start = start_offset + 8
        name_end = data_bytes.find(b'\x00', name_start)
        if name_end == -1: # No null terminator, read until end
            self.name = data_bytes[name_start:].decode('ascii', errors='ignore')
        else:
            self.name = data_bytes[name_start:name_end].decode('ascii', errors='ignore')

    def __str__(self):
        return (f"ItemStruct:\n"
                f"  ID: {self.item_id}\n"
                f"  Quantity: {self.quantity}\n"
                f"  Name: '{self.name}'")

# The "ITEM" pattern starts at offset 24 in simulated_binary_data
second_struct_offset = 24 
found_item = ItemStruct(simulated_binary_data, second_struct_offset)
print(found_item)

# Let's also parse the first one to show it works
first_struct_offset = 4
found_name = ItemStruct(simulated_binary_data, first_struct_offset)
print("\n--- Another instance ---")
print(found_name)

Muita rakenteiden vihjeitä

Yksinkertaisten kuvioiden ja ristiviitteiden lisäksi skriptit voivat etsiä seuraavia asioita:

  • Tasaus: Tietotyypit sijoitetaan usein tiettyjen tavurajojen mukaisesti. Esimerkiksi 4 tavun kokonaisluvut sijoitetaan osoitteisiin, jotka ovat jaollisia neljällä.
  • Vtable-taulukot: C++:ssa oliot alkavat usein osoittimella "virtuaalisten metodien taulukkoon" (vtable), mikä on vahva merkki oliosta.
  • Yleiset funktioargumentit: Jos kirjastofunktio odottaa syötteekseen tiettyä rakennetta, skriptit voivat tunnistaa kyseiseen funktioon tehdyt kutsut ja päätellä argumenttien rakenteen.

Tietorakenteita koskeva haaste

Tietorakenteiden palauttamisen automatisoinnissa etsitään merkityksellisiä kuvioita raakadatasta binäärimuodossa.

Mikä seuraavista EI ole ensisijainen syy siihen, miksi skriptien käyttö on välttämätöntä tietorakenteiden tunnistamisessa obfuskoiduista binääreistä?

Kertaus: automatisoitu rakenteiden palauttaminen

Olemme oppineet, että tietorakenteiden palauttaminen on tärkeää käännettyjen ohjelmien ymmärtämiseksi. Manuaalinen tunnistaminen on vaikeaa kadonneiden lähdetietojen ja optimointien vuoksi.

Skriptit auttavat seuraavasti:

  • etsimällä tietotyyppeihin viittaavia tavukuvioita
  • analysoimalla muistipaikkoihin liittyviä ristiviitteitä
  • määrittämällä rakenteita ohjelmallisesti käänteisen suunnittelun työkaluissa

Tämä muuttaa raakatavut ymmärrettäväksi ohjelmalogiikaksi ja helpottaa monimutkaista analyysiä huomattavasti!

Aloita maksutta

Opi Assembly tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
12
Oppitunnit
48

Usein kysytyt kysymykset

Onko oppitunti ”Tietorakenteiden palauttamisen automatisointi” ilmainen?

Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa Ohjelmistojen käänteinen suunnittelu ja binäärien analysoinnin perusteet-oppimispolun 3 oppituntia, myös oppitunnin “Tietorakenteiden palauttamisen automatisointi”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Ohjelmistojen käänteinen suunnittelu ja binäärien analysoinnin perusteet-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Tietorakenteiden palauttamisen automatisointi”?

Kehittäkää komentojonoja monimutkaisten tietorakenteiden automaattiseen tunnistamiseen ja rekonstruointiin hämärretyistä binääreistä. Harjoittelet Ohjelmistojen käänteinen suunnittelu ja binäärien analysoinnin perusteet-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Ohjelmistojen käänteinen suunnittelu ja binäärien analysoinnin perusteet-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Ohjelmistojen käänteinen suunnittelu ja binäärien analysoinnin perusteet-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 2/4.

Kuinka kauan ”Tietorakenteiden palauttamisen automatisointi”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Ohjelmistojen käänteinen suunnittelu ja binäärien analysoinnin perusteet-oppitunnilla?

Kyllä. Jokainen Ohjelmistojen käänteinen suunnittelu ja binäärien analysoinnin perusteet-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. IDAPython- ja Ghidra-komentojonot
  2. Tietorakenteiden palauttamisen automatisointi
  3. Binäärien paikkaustekniikat
  4. FLIRT-tunnisteet ja kirjastofunktioiden tunnistaminen
← Takaisin: Ohjelmistojen käänteinen suunnittelu ja binäärien analysoinnin perusteet