GUIDA Calcolare la lunghezza in bytes di una funzione in C/C++ e difficoltà varie

Pubblicità

DispatchCode

Moderatore
Staff Forum
Utente Èlite
Messaggi
2,332
Reazioni
1,928
Punteggio
134

Calcolare la lunghezza di una funzione​

1. Introduzione​

Non è una domanda comune, ma vuoi per curiosità o per necessità, a qualcuno capita di chiedersi "ma, come posso sapere quanta è lunga una funzione in bytes?". Queti sono alcuni esempi:

Find size of a function in C
Is it possible to calculate function length at compile time in C?

E per necessità, qualcuno si inventa soluzioni interessanti:
Calculate C function size x86 and x64
Il metodo presentato in quell'articolo è piuttosto semplice: consiste nell'inserire nel programma una porzione di codice inutile, inserita spesso quando un file viene compilato con il flag DEBUG, che prende forma nell'istruzione INT 3 (0xCC). In questo caso vengono usate più ripetizioni della medesima istruzioni, inserendo un totale di 8bytes.
Poi, considerando che il compilatore va a rimuovere il codice inutile e che del codice dopo il "return" ricade proprio in questo caso, l'autore dell'articolo utilizza la parola chiave volatile, così nulla viene rimosso. Nel suo screenshot infatti vedrete presenti quei bytes. Di conseguenza, passando l'indirizzo della funzione, si capisce qual è la fine grazie a quella sequenza di bytes inserita in fase di compilazione.

2. Perchè è complicato individuare la fine di una funzione?​

E' complicato per una serie di fattori. Diciamo che una funzione termina con il classico "return", che in assembly lo si può rappresentare dall'istruzione RET. Se fosse così semplice, basterebbe cercare nel codice macchina l'opcode di RET (che è 0xC3); un gioco da ragazzi insomma.
Ed ecco le complicazioni: se quel 0xC3 in realtà fosse un byte che fa parte di un'altra istruzione? Magari un valore costante come il numero 195 (0xC3 in esadecimale) oppure il cosiddetto "spiazzamento" (displacement) piuttosto che un'altra parte dell'istruzione.
Per capire se il byte che stiamo cercando è l'opcode cercato, è necessario stabilire di quanti byte è composta un'istruzione. Avevo già trattato l'argomento, in realtà senza un vero e proprio articolo, ma proponendo un mio progetto (MCA). Potete leggerne di più al seguente topic Decodificare la lunghezza delle istruzioni di x86 e x64.
Stabilire quanti byte compongono un'istruzione non è semplice, in quanto questa architettura (x86 e x64) ha istruzioni con lunghezza variabile.

Supponiamo però che questo problema non esista, e torniamo alla prima semplificazione: cercare il byte 0xC3. Bene, ora l'abbiamo trovato ma... se fossero presenti "ret" multipli? Anche questo può verificarsi. Non solo, ci sono anche casi nei quali il "ret" non è l'ultima istruzione della funzione, in quanto un qualche tipo di salto (JMP o uno dei salti condizionali,diciamo un IF) lo raggiunge.

example2_2returns.png

In un caso come questo, non si riuscirebbe a stabilire l'effettiva lunghezza, in quanto il primo RET, verrebbe rilevato come termine della funzione.

3. Disassembly: identificare una funzione​

Ciò che presento io è un altro metodo, alternativo, rispetto a quello linkato in apertura. Non è ancora del tutto completo, sono certo ci siano situazioni e casi non "coperti" vista la complessità dell'argomento (e dei test limitati che ho condotto). Ciò che so di non aver gestito sono le jump table, e purtroppo in questi casi la lunghezza viene identificata in modo errato, quindi non sto presentando una soluzione definitiva e priva di errori. Un caso di esempio verrà presentato in seguito.

Proseguendo però con il disassembly, consideriamo questo codice in C:
C:
void bubble_sort(int *array) {
    printf("Bubble sort");
    for(int i=0; i<10; i++) {
        for(int j=i+1; j<10; j++) {
            if(array[i] > array[j]) {
                int tmp = array[i];
                array[i] = array[j];
                array[j] = tmp;
            }
        }
    }
}

Utilizzando GCC (MinGw, in ambiente Windows) il codice generato è quello visualizzato nello screenshot sottostante:

gcc_bubble.png

Nell'immagine si vedono anche distintamente i due loop annidati (i JMP in cima con i due JLE e l'if, l'altro JLE). Questa funzione non ha nulla di complesso, ha solo un'istruzione RET. Ora, come funziona l'algoritmo?
Ho deciso di utilizzare un'approccio "misto" che mi consentisse di seguire il flusso del codice, ma procedendo anche linearmente, istruzione per istruzione. Ciò che faccio è seguire subito i JMP e aggiungere l'istruzione successiva a una "coda futura" (future paths). I Jcc (sallti condizionati, JE, JNE, JG,...) invece non li seguo subito, ma aggiungo aggiungo l'indirizzo target alla coda e poi procedo all'istruzione successiva. Non vado in profondità attualmente, quindi le CALL le ignoro, le tratto come qualsiasi altra istruzione.
Gli opcode RET (0xC3) e 0xCC provocano il termine di quello che è un loop. Il loop prosegue sino a che la coda è vuota. La fine di un "path" coincide con l'elaborazione di RET, 0xCC oppure quando viene rilevato che l'indirizzo attuale è già stato visitato. Ad ogni iterazione infatti ciascun indirizzo viene aggiunto a un array (dinamico).
Il raggiungimendo di questo "stato terminale" provoca sempre la lettura dalla coda (future paths): se un indirizzo è presente, viene "caricato" e il disassembly prosegue da questo indirizzo; se la coda è vuota, abbiamo analizzato l'intera funzione.

Riporto il codice completo, in C:
C:
#include "function_length.h"


vector* instrFlowLength(char *pMemory, enum supported_architecture arch)
{
    int bytes_len = 0;
    uint32_t addr = ((int)pMemory);

    queue *future_paths = queue_init();
    vector *visited = vector_init();

    char *tmp_addr = pMemory;
    while(true)
    {
        struct instruction instr;
        mca_decode(&instr, arch,tmp_addr,0);

        if(instr.op == 0xc3 || instr.op == 0xCC)
        {
            if(queue_empty(future_paths))
            {
                if(instr.op == 0xC3)
                    vector_push_back(visited,addr+instr.length);

                queue_free(future_paths);
                return visited;
            }
            vector_push_back(visited,addr);

            tmp_addr = 0;
            tmp_addr += queue_dequeue(future_paths);
            addr = (uint32_t) tmp_addr;
        }
        else
        {
            if(vector_find(visited, addr))
            {
                if(queue_empty(future_paths)) {
                    queue_free(future_paths);
                    return visited;
                }

                tmp_addr = 0;
                tmp_addr += queue_dequeue(future_paths);
                addr = (uint32_t) tmp_addr;
            }
            else
            {

                vector_push_back(visited, addr);

                if (instr.jcc_type == JCC_FAR || instr.jcc_type == JCC_SHORT)
                {
                    if (queue_find(future_paths,instr.label) == 0)
                        queue_enqueue(future_paths,instr.label);
                }

                bytes_len += instr.length;
                addr += instr.length;
                tmp_addr += instr.length;

                if (instr.jcc_type == JMP_FAR || instr.jcc_type == JMP_SHORT)
                {
                    if (queue_find(future_paths,addr))
                        queue_enqueue(future_paths,addr);

                    tmp_addr = 0;
                    tmp_addr += instr.label;
                    addr = instr.label;
                }
            }
        }
    }
}

int compare(const void * n1, const void * n2)
{
    return (int)( *(uint32_t *)n1 - *(uint32_t*)n2 );
}

pFunctionInfo getFunctionLength(char *buffer, enum supported_architecture arch)
{
    pFunctionInfo f_info = calloc(1,sizeof(functionInfo));
    vector *visited = instrFlowLength(buffer, arch);

    qsort(visited->vect, visited->tos, sizeof(uint32_t), compare);

    uint32_t min = visited->vect[0];
    uint32_t max = visited->vect[visited->tos-1];

    f_info->pVisited = visited;
    f_info->length = (int)(max-min);

    return f_info;
}

Tutto il codice è stato integrato in MCA e può essere compilato/utilizzato anche da un codice in C++, non ci sono problemi. Ho creato un main che consente la lettura del codice di una funzione e ne restituisce la lunghezza, oltre che tutte le istruzioni che la compongono. Di seguito riporterò alcune parti, spiegandole, e per chiarezza lascerò anche sotto spoiler l'intero output (è un pò lungo...).
L'output che riporto e andrò a spiegare è stato eseguito sulla funzione bubble sort dello screenshot riportato sopra.

Codice:
Reading function machine code at address 0x402620... Done!
Function Length: 179-bytes, decoded 54 instructions.

Addresses of instructions that has been decoded:

402620, 402621, 402623, 402626, 40262D, 402632, 402639, 40263E,
402641, 402644, 402647, 402649, 40264C, 402653, 402656, 402658,
40265A, 40265D, 402664, 402667, 402669, 40266B, 40266D, 40266F,
402672, 402679, 40267C, 40267E, 402680, 402683, 402686, 40268D,
402690, 402692, 402695, 40269C, 40269F, 4026A1, 4026A3, 4026A5,
4026A8, 4026AF, 4026B2, 4026B4, 4026B7, 4026B9, 4026BD, 4026C1,
4026C3, 4026C7, 4026CB, 4026D1, 4026D2, 4026D3,

La prima info interessante è l'entry point della funzione, che se andate a guardare lo screen, coincide con quello riportato qui. L'altra info interessante è proprio la sua lunghezza in bytes. Vengono anche riportati tutti gli indirizzi delle istruzioni che sono state elaborate; potrebbe tornare utile per qualche motivo avere l'elenco degli indirizzi e da lì risalire facilmente all'istruzione e analizzarla singolarmente con MCA, o chissà, anche modificarla.
Proseguo con la parte successiva dell'output:

Codice:
Start disassembly the addresses range: [0x402620, 0x4026D3]

Instr. VA: 0x402620
RAW bytes (hex): 55
Instr. length: 1
Print instruction fields:
        Located Prefixes 0:

        OP: 0x55
------------------------------------------------
Instr. VA: 0x402621
RAW bytes (hex): 89 E5
Instr. length: 2
Print instruction fields:
        Located Prefixes 0:

        OP: 0x89
        mod_reg_rm: 0xE5
------------------------------------------------
Instr. VA: 0x402623
RAW bytes (hex): 83 EC 28
Instr. length: 3
Print instruction fields:
        Located Prefixes 0:

        OP: 0x83
        mod_reg_rm: 0xEC
        Iimm: 0x28
------------------------------------------------
Instr. VA: 0x402626
RAW bytes (hex): C7 04 24 78 D1 40 00
Instr. length: 7
Print instruction fields:
        Located Prefixes 0:

        OP: 0xC7
        mod_reg_rm: 0x4
        SIB byte: 0x24
        Iimm: 0x40D178
------------------------------------------------
Instr. VA: 0x40262D
RAW bytes (hex): E8 82 1A 00 00
Instr. length: 5
Print instruction fields:
        Located Prefixes 0:

        OP: 0xE8
        Iimm: 0x1A82
------------------------------------------------
Instr. VA: 0x402632
RAW bytes (hex): C7 45 F4 00 00 00 00
Instr. length: 7
Print instruction fields:
        Located Prefixes 0:

        OP: 0xC7
        mod_reg_rm: 0x45
        disp (1): 0xF4
        Iimm: 0x0
------------------------------------------------
Instr. VA: 0x402639
RAW bytes (hex): E9 89 00 00 00
Instr. length: 5

Instr. is a jump with target address: 0x4026C7
Print instruction fields:
        Located Prefixes 0:

        OP: 0xE9
        Iimm: 0x89
------------------------------------------------

Penso ci sia poco da aggiungere: si tratta di tutte le info riguardanti ciascuna istruzione che MCA ha disassemblato (notate anche l'identificazione di un salto JMP/JCC; è il modo in cui il codice che effettua il conteggio dei bytes che compongono la funzione, verifica se si tratta di un JMP/JCC).

Riporto anche il medesimo codice compilato però con MSVC:

msvc_bubble.png

Riporto solo alcune istruzioni:
Codice:
Reading function machine code at address 0x812880... Done!
Function Length: 140-bytes, decoded 50 instructions.

Addresses of instructions that has been decoded:

812880, 812881, 812883, 812886, 812887, 81288C, 812891, 812894,
81289B, 81289D, 8128A0, 8128A3, 8128A6, 8128AA, 8128AC, 8128AF,
8128B2, 8128B5, 8128B7, 8128BA, 8128BD, 8128C0, 8128C4, 8128C6,
8128C9, 8128CC, 8128CF, 8128D2, 8128D5, 8128D8, 8128DA, 8128DD,
8128E0, 8128E3, 8128E6, 8128E9, 8128EC, 8128EF, 8128F2, 8128F5,
8128F8, 8128FB, 8128FE, 812901, 812904, 812906, 812908, 812909,
81290B, 81290C,

Start disassembly the addresses range: [0x812880, 0x81290C]

Instr. VA: 0x812880
RAW bytes (hex): 55
Instr. length: 1
Print instruction fields:
        Located Prefixes 0:

        OP: 0x55
------------------------------------------------
Instr. VA: 0x812881
RAW bytes (hex): 8B EC
Instr. length: 2
Print instruction fields:
        Located Prefixes 0:

        OP: 0x8B
        mod_reg_rm: 0xEC
------------------------------------------------

Gli indirizzi differiscono nel byte più alto con MSVC in quanto è presente la randomizzazione (ASLR). L'altra parte è infatti uguale, come 0x812880 e il primo indirizzo visibile nell'immagine.
Senza l'utilizzo di flags, il codice prodotto da MSVC è di 39-bytes più corto. Riporto anche il medesimo codice, ma compilato utilizzando -O2 (MinGw) e /O2 (MSVC).

MinGW, bubble sort:
gcc_bubble_o2.png

L'output parziale è il seguente:
Codice:
Reading function machine code at address 0x4022F0... Done!
Function Length: 104-bytes, decoded 36 instructions.

Addresses of instructions that has been decoded:

4022F0, 4022F1, 4022F3, 4022F4, 4022F5, 4022F6, 4022F9, 402300,
402304, 402309, 402311, 402316, 402319, 402320, 402323, 402326,
402328, 40232A, 40232C, 40232E, 402330, 402332, 402335, 402338,
40233A, 40233E, 402341, 402344, 402346, 40234A, 402350, 402353,
402354, 402355, 402356, 402358,

Start disassembly the addresses range: [0x4022F0, 0x402358]

Instr. VA: 0x4022F0
RAW bytes (hex): 55
Instr. length: 1
Print instruction fields:
        Located Prefixes 0:

        OP: 0x55
------------------------------------------------
Instr. VA: 0x4022F1
RAW bytes (hex): 31 ED
Instr. length: 2
Print instruction fields:
        Located Prefixes 0:

        OP: 0x31
        mod_reg_rm: 0xED
------------------------------------------------

E MSVC:

msvc_bubble_o2.png

Codice:
Reading function machine code at address 0x8D1E90... Done!
Function Length: 72-bytes, decoded 33 instructions.

Addresses of instructions that has been decoded:

8D1E90, 8D1E91, 8D1E92, 8D1E93, 8D1E94, 8D1E99, 8D1E9E, 8D1EA2,
8D1EA7, 8D1EAA, 8D1EAC, 8D1EAF, 8D1EB0, 8D1EB2, 8D1EB5, 8D1EB7,
8D1EBA, 8D1EBC, 8D1EBE, 8D1EC0, 8D1EC2, 8D1EC5, 8D1EC6, 8D1EC9,
8D1ECB, 8D1ECC, 8D1ECF, 8D1ED2, 8D1ED4, 8D1ED5, 8D1ED6, 8D1ED7,
8D1ED8,

Start disassembly the addresses range: [0x8D1E90, 0x8D1ED8]

Instr. VA: 0x8D1E90
RAW bytes (hex): 53
Instr. length: 1
Print instruction fields:
        Located Prefixes 0:

        OP: 0x53
------------------------------------------------
Instr. VA: 0x8D1E91
RAW bytes (hex): 55
Instr. length: 1
Print instruction fields:
        Located Prefixes 0:

        OP: 0x55
------------------------------------------------

4. Problemi nel disassembly e "magie" dei compilatori​

Il problema principale è sicuramente dovuto alle jump table nel caso di switch e magari di if/elseif. Potrebbero esserci altri problemi in caso di funzioni che non hanno un ritorno esplicito con RET, ma sono casi che andrebbero creati adhoc per essere poi testati appositamente. Non ho testato con eseguibili prodotti da altri compilatori, ma è probabile che in futuro farò anche questo (CLang ad esempio).

Ma veniamo al problema, che ahimè, non è facilmente risolvibile. Ho creato una funzione senza un significato preciso, il cui corpo è il seguente:

C:
int example1(int n) {
    printf("example1");
    int c = 0;
    for(int i=0; i<10; i++) {
        for(int j=i; j<n; j++) {
            switch (n%i) {
                case 2:
                    return 3;
                case 10:
                    return 23;
                case 3:
                    return 412;
                case 98:
                    return 32;
                default:
                    c++;
            }
        }
    }
    return c;
}

Iniziamo da MinGw senza flag:
example1_gcc.png

Nulla di particolare, cicli e "if". Questo è il codice prodotto invece da MSVC:

example1_msvc.png

NOTA: chiedo venia, non mi ero reso conto di aver compilato questa versione: la variabile i del ciclo for deve essere inizializzata a 1; per il resto è tutto corretto, quindi l'istruzione dell'assegnamento del valore a LOCAL.1 verrà fatta con 1 e non con 0 come riportato negli screen.

In particolare guardate questo codice:

Codice:
CPU Disasm
Address   Hex dump          Command                                  Comments
00C229B7  |.  0FB682 0C2AC2 ||MOVZX EAX,BYTE PTR DS:[EDX+0C22A0C]    ; Switch (cases 0..4, 5 exits)
00C229BE  |.  FF2485 F829C2 ||JMP DWORD PTR DS:[EAX*4+0C229F8]

all'indirizzo 0x00C22A0C si trovano dei valori, dei bytes, che riporto sotto spoiler:

Codice:
CPU Disasm
Address   Hex dump          Command                                  Comments
00C22A0C   .  00            DB 00
00C22A0D   .  01            DB 01
00C22A0E   .  04            DB 04
00C22A0F   .  04            DB 04
00C22A10   .  04            DB 04
00C22A11   .  04            DB 04
00C22A12   .  04            DB 04
00C22A13   .  04            DB 04
00C22A14   .  02            DB 02
00C22A15   .  04            DB 04
00C22A16   .  04            DB 04
00C22A17   .  04            DB 04
00C22A18   .  04            DB 04
00C22A19   .  04            DB 04
00C22A1A   .  04            DB 04
00C22A1B   .  04            DB 04
00C22A1C   .  04            DB 04
00C22A1D   .  04            DB 04
00C22A1E   .  04            DB 04
00C22A1F   .  04            DB 04
00C22A20   .  04            DB 04
00C22A21   .  04            DB 04
00C22A22   .  04            DB 04
00C22A23   .  04            DB 04
00C22A24   .  04            DB 04
00C22A25   .  04            DB 04
00C22A26   .  04            DB 04
00C22A27   .  04            DB 04
00C22A28   .  04            DB 04
00C22A29   .  04            DB 04
00C22A2A   .  04            DB 04
00C22A2B   .  04            DB 04
00C22A2C   .  04            DB 04
00C22A2D   .  04            DB 04
00C22A2E   .  04            DB 04
00C22A2F   .  04            DB 04
00C22A30   .  04            DB 04
00C22A31   .  04            DB 04
00C22A32   .  04            DB 04
00C22A33   .  04            DB 04
00C22A34   .  04            DB 04
00C22A35   .  04            DB 04
00C22A36   .  04            DB 04
00C22A37   .  04            DB 04
00C22A38   .  04            DB 04
00C22A39   .  04            DB 04
00C22A3A   .  04            DB 04
00C22A3B   .  04            DB 04
00C22A3C   .  04            DB 04
00C22A3D   .  04            DB 04
00C22A3E   .  04            DB 04
00C22A3F   .  04            DB 04
00C22A40   .  04            DB 04
00C22A41   .  04            DB 04
00C22A42   .  04            DB 04
00C22A43   .  04            DB 04
00C22A44   .  04            DB 04
00C22A45   .  04            DB 04
00C22A46   .  04            DB 04
00C22A47   .  04            DB 04
00C22A48   .  04            DB 04
00C22A49   .  04            DB 04
00C22A4A   .  04            DB 04
00C22A4B   .  04            DB 04
00C22A4C   .  04            DB 04
00C22A4D   .  04            DB 04
00C22A4E   .  04            DB 04
00C22A4F   .  04            DB 04
00C22A50   .  04            DB 04
00C22A51   .  04            DB 04
00C22A52   .  04            DB 04
00C22A53   .  04            DB 04
00C22A54   .  04            DB 04
00C22A55   .  04            DB 04
00C22A56   .  04            DB 04
00C22A57   .  04            DB 04
00C22A58   .  04            DB 04
00C22A59   .  04            DB 04
00C22A5A   .  04            DB 04
00C22A5B   .  04            DB 04
00C22A5C   .  04            DB 04
00C22A5D   .  04            DB 04
00C22A5E   .  04            DB 04
00C22A5F   .  04            DB 04
00C22A60   .  04            DB 04
00C22A61   .  04            DB 04
00C22A62   .  04            DB 04
00C22A63   .  04            DB 04
00C22A64   .  04            DB 04
00C22A65   .  04            DB 04
00C22A66   .  04            DB 04
00C22A67   .  04            DB 04
00C22A68   .  04            DB 04
00C22A69   .  04            DB 04
00C22A6A   .  04            DB 04
00C22A6B   .  04            DB 04
00C22A6C   .  03            DB 03

sono in totale 96-bytes.
Riporto una parte di codice dello screen, quella davvero interessante:
Codice:
CPU Disasm
Address   Hex dump          Command                                  Comments
00C2299B  |.  8B45 08       ||MOV EAX,DWORD PTR SS:[ARG.1]
00C2299E  |.  99            ||CDQ
00C2299F  |.  F77D FC       ||IDIV DWORD PTR SS:[LOCAL.1]
00C229A2  |.  8955 F8       ||MOV DWORD PTR SS:[LOCAL.2],EDX
00C229A5  |.  8B4D F8       ||MOV ECX,DWORD PTR SS:[LOCAL.2]
00C229A8  |.  83E9 02       ||SUB ECX,2
00C229AB  |.  894D F8       ||MOV DWORD PTR SS:[LOCAL.2],ECX
00C229AE  |.  837D F8 60    ||CMP DWORD PTR SS:[LOCAL.2],60
00C229B2  |.  77 2D         ||JA SHORT 00C229E1
00C229B4  |.  8B55 F8       ||MOV EDX,DWORD PTR SS:[LOCAL.2]
00C229B7  |.  0FB682 0C2AC2 ||MOVZX EAX,BYTE PTR DS:[EDX+0C22A0C]    ; Switch (cases 0..4, 5 exits)
00C229BE  |.  FF2485 F829C2 ||JMP DWORD PTR DS:[EAX*4+0C229F8]

ARG.1 è il parametro passato alla funzione, la variabile n. LOCAL.1 è la variabile "i". Viene esteso il valore di EAX da double word a quad word (azzerando il registro EDX), e successivamente avviene la divisione; il registro EDX conterrà il resto della divisione. Questo valore viene assegnato a ECX che viene sottratto di 2 unità. Questo valore viene poi confrontato con il numero 0x60, ovvero 96. Avete già visto questo valore? Già, i bytes della lookup table sono 96. In sostanza, visto che i "case" dello switch non coprono i primi 2 numeri (0 e 1) e che il case con il valore più alto è 98, il compilatore ha prodotto una tabella di 96-bytes, ai quali accede usando il resto della divisione - 2 unità.

Un esempio numerico: diciamo che EAX (il valore di n) sia 10 e che LOCAL.1 sia alla terza iterazione (i=3). Ciò che si verifica è che la divisione 10/3=3 con resto 1 (quindi EDX = 1). ECX = EDX, quindi avverrà la sottrazione ECX-2 = -1.
Questo valore viene confrontato con 96 (0x60), ma il confronto avviene tenendo conto del valore unsigned del primo operando (che nella CMP è il resto, LOCAL.2): questo significa che il confronto avverrà tra 0xFFFFFFFF che è molto più grande di 0x60. Trattandosi di un valore molto più grande, il salto JA avviene e quindi viene eseguito il case di default all'indirizzo 0x00C229E1:

Codice:
CPU Disasm
Address   Hex dump          Command                                  Comments
00C229B2  |. /77 2D         ||JA SHORT 00C229E1
00C229B4  |. |8B55 F8       ||MOV EDX,DWORD PTR SS:[LOCAL.2]
00C229B7  |. |0FB682 0C2AC2 ||MOVZX EAX,BYTE PTR DS:[EDX+0C22A0C]    ; Switch (cases 0..4, 5 exits)
00C229BE  |. |FF2485 F829C2 ||JMP DWORD PTR DS:[EAX*4+0C229F8]
00C229C5  |> |B8 03000000   ||MOV EAX,3                              ; Case 0 of switch main.0C229B7
00C229CA  |. |EB 25         ||JMP SHORT 00C229F1
00C229CC  |> |B8 17000000   ||MOV EAX,17                             ; Case 2 of switch main.0C229B7
00C229D1  |. |EB 1E         ||JMP SHORT 00C229F1
00C229D3  |> |B8 9C010000   ||MOV EAX,19C                            ; Case 1 of switch main.0C229B7
00C229D8  |. |EB 17         ||JMP SHORT 00C229F1
00C229DA  |> |B8 20000000   ||MOV EAX,20                             ; Case 3 of switch main.0C229B7
00C229DF  |. |EB 10         ||JMP SHORT 00C229F1
00C229E1  |> \8B4D F0       ||MOV ECX,DWORD PTR SS:[LOCAL.4]         ; Case 4 of switch main.0C229B7
00C229E4  |.  83C1 01       ||ADD ECX,1
00C229E7  |.  894D F0       ||MOV DWORD PTR SS:[LOCAL.4],ECX

Prendiamo un'iterazione successiva, quando avremo EDX = 3. In questo caso la sottrazione di 1 unità porterà ECX a 1. Questo valore è più piccolo di 0x60 (96d), quindi il JA non avviene.
Quando il JA non avviene viene eseguito il codice riguardante le tabelle di lookup: prima avviene il lookup del case, quindi si usa il resto che è 1 come indice nell'insieme di byte mostrato sopra: 0x0C22A0C = 0x0C22A0D. Se guardate i bytes mostrati sopra, vedrete che il valore contenuto a questa locazione è il numero 1.
Questo numero viene moltiplicato per 4 (perchè stiamo indirizzando una DWORD, quindi 4-byt) e sommato a 0x0C229F8 dando come risultato 0x00C229FC, indirizzo al quale otteniamo 0x00C229D3; a partire dalla locazione 0x0C229F8 infatti la tabella contiene questi dati:
Codice:
CPU Disasm
Address   Hex dump          Command                                  Comments
00C229F8   . \C529C200      DD 00C229C5
00C229FC   .  D329C200      DD 00C229D3
00C22A00   .  CC29C200      DD 00C229CC
00C22A04   .  DA29C200      DD 00C229DA
00C22A08   .  E129C200      DD 00C229E1

come potete vedere viene eseguito questo codice:
Codice:
00C229D3  |> |B8 9C010000   ||MOV EAX,19C                            ; Case 1 of switch main.0C229B7
00C229D8  |. |EB 17         ||JMP SHORT 00C229F1

il vlore 0x19C in decimale è il numero 412 e guardando il codice... vedrete che si tratta del case (con resto) 3.

Questa è la parte "magica", se vogliamo, del lavorone fatto dietro dal compilatore. Implementare un algoritmo che riesca a "capire" che si tratta di una jump table e risalire ai vari case, è oltre a ciò che posso fare ora (ammesso che poi riesca a implementare una cosa come questa) anche per motivi di tempo. In futuro magari proseguirò, chissà...

Ma tornando ai codici, guardate usando O2 con GCC (MinGw) cosa si ottiene:

example1_gcc_o2.png

il codice viene già di molto semplificato. Anche in questo caso l'algoritmo che ottiene la lunghezza funziona correttamente:
Codice:
Reading function machine code at address 0x402340... Done!
Function Length: 108-bytes, decoded 44 instructions.

Addresses of instructions that has been decoded:

402340, 402341, 402343, 402344, 402347, 40234E, 402352, 402357,
40235C, 40235E, 402360, 402362, 402363, 402365, 402368, 40236A,
40236D, 40236F, 402372, 402374, 402377, 402379, 40237B, 40237C,
402380, 402383, 402386, 402388, 40238B, 40238D, 40238E, 40238F,
402390, 402395, 402398, 40239A, 40239B, 40239C, 4023A0, 4023A5,
4023A8, 4023AA, 4023AB, 4023AC,

Start disassembly the addresses range: [0x402340, 0x4023AC]

Instr. VA: 0x402340
RAW bytes (hex): 56
Instr. length: 1
Print instruction fields:
        Located Prefixes 0:

        OP: 0x56
------------------------------------------------
Instr. VA: 0x402341
RAW bytes (hex): 31 F6
Instr. length: 2
Print instruction fields:
        Located Prefixes 0:

        OP: 0x31
        mod_reg_rm: 0xF6
------------------------------------------------
Instr. VA: 0x402343
RAW bytes (hex): 53
Instr. length: 1
Print instruction fields:
        Located Prefixes 0:

        OP: 0x53
------------------------------------------------
Instr. VA: 0x402344
RAW bytes (hex): 83 EC 14
Instr. length: 3
Print instruction fields:
        Located Prefixes 0:

        OP: 0x83
        mod_reg_rm: 0xEC
        Iimm: 0x14
------------------------------------------------
Instr. VA: 0x402347
RAW bytes (hex): C7 04 24 D4 75 40 00
Instr. length: 7
Print instruction fields:
        Located Prefixes 0:

        OP: 0xC7
        mod_reg_rm: 0x4
        SIB byte: 0x24
        Iimm: 0x4075D4
------------------------------------------------
Instr. VA: 0x40234E
RAW bytes (hex): 8B 5C 24 20
Instr. length: 4
Print instruction fields:
        Located Prefixes 0:

        OP: 0x8B
        mod_reg_rm: 0x5C
        SIB byte: 0x24
        disp (1): 0x20
------------------------------------------------
Instr. VA: 0x402352
RAW bytes (hex): E8 0D 18 00 00
Instr. length: 5
Print instruction fields:
        Located Prefixes 0:

        OP: 0xE8
        Iimm: 0x180D
------------------------------------------------
Instr. VA: 0x402357
RAW bytes (hex): B9 01 00 00 00
Instr. length: 5
Print instruction fields:
        Located Prefixes 0:

        OP: 0xB9
        Iimm: 0x1
------------------------------------------------
Instr. VA: 0x40235C
RAW bytes (hex): 39 CB
Instr. length: 2
Print instruction fields:
        Located Prefixes 0:

        OP: 0x39
        mod_reg_rm: 0xCB
------------------------------------------------
Instr. VA: 0x40235E
RAW bytes (hex): 7E 20
Instr. length: 2

Instr. is a jump with target address: 0x402380
Print instruction fields:
        Located Prefixes 0:

        OP: 0x7E
        Iimm: 0x20
------------------------------------------------
Instr. VA: 0x402360
RAW bytes (hex): 89 D8
Instr. length: 2
Print instruction fields:
        Located Prefixes 0:

        OP: 0x89
        mod_reg_rm: 0xD8
------------------------------------------------
Instr. VA: 0x402362
RAW bytes (hex): 99
Instr. length: 1
Print instruction fields:
        Located Prefixes 0:

        OP: 0x99
------------------------------------------------
Instr. VA: 0x402363
RAW bytes (hex): F7 F9
Instr. length: 2
Print instruction fields:
        Located Prefixes 0:

        OP: 0xF7
        mod_reg_rm: 0xF9
------------------------------------------------
Instr. VA: 0x402365
RAW bytes (hex): 8D 04 33
Instr. length: 3
Print instruction fields:
        Located Prefixes 0:

        OP: 0x8D
        mod_reg_rm: 0x4
        SIB byte: 0x33
------------------------------------------------
Instr. VA: 0x402368
RAW bytes (hex): 29 C8
Instr. length: 2
Print instruction fields:
        Located Prefixes 0:

        OP: 0x29
        mod_reg_rm: 0xC8
------------------------------------------------
Instr. VA: 0x40236A
RAW bytes (hex): 83 FA 02
Instr. length: 3
Print instruction fields:
        Located Prefixes 0:

        OP: 0x83
        mod_reg_rm: 0xFA
        Iimm: 0x2
------------------------------------------------
Instr. VA: 0x40236D
RAW bytes (hex): 74 31
Instr. length: 2

Instr. is a jump with target address: 0x4023A0
Print instruction fields:
        Located Prefixes 0:

        OP: 0x74
        Iimm: 0x31
------------------------------------------------
Instr. VA: 0x40236F
RAW bytes (hex): 83 FA 03
Instr. length: 3
Print instruction fields:
        Located Prefixes 0:

        OP: 0x83
        mod_reg_rm: 0xFA
        Iimm: 0x3
------------------------------------------------
Instr. VA: 0x402372
RAW bytes (hex): 74 1C
Instr. length: 2

Instr. is a jump with target address: 0x402390
Print instruction fields:
        Located Prefixes 0:

        OP: 0x74
        Iimm: 0x1C
------------------------------------------------
Instr. VA: 0x402374
RAW bytes (hex): 83 C6 01
Instr. length: 3
Print instruction fields:
        Located Prefixes 0:

        OP: 0x83
        mod_reg_rm: 0xC6
        Iimm: 0x1
------------------------------------------------
Instr. VA: 0x402377
RAW bytes (hex): 39 C6
Instr. length: 2
Print instruction fields:
        Located Prefixes 0:

        OP: 0x39
        mod_reg_rm: 0xC6
------------------------------------------------
Instr. VA: 0x402379
RAW bytes (hex): 75 EF
Instr. length: 2

Instr. is a jump with target address: 0x40236A
Print instruction fields:
        Located Prefixes 0:

        OP: 0x75
        Iimm: 0xEF
------------------------------------------------
Instr. VA: 0x40237B
RAW bytes (hex): 90
Instr. length: 1
Print instruction fields:
        Located Prefixes 0:

        OP: 0x90
------------------------------------------------
Instr. VA: 0x40237C
RAW bytes (hex): 8D 74 26 00
Instr. length: 4
Print instruction fields:
        Located Prefixes 0:

        OP: 0x8D
        mod_reg_rm: 0x74
        SIB byte: 0x26
        disp (1): 0x0
------------------------------------------------
Instr. VA: 0x402380
RAW bytes (hex): 83 C1 01
Instr. length: 3
Print instruction fields:
        Located Prefixes 0:

        OP: 0x83
        mod_reg_rm: 0xC1
        Iimm: 0x1
------------------------------------------------
Instr. VA: 0x402383
RAW bytes (hex): 83 F9 0A
Instr. length: 3
Print instruction fields:
        Located Prefixes 0:

        OP: 0x83
        mod_reg_rm: 0xF9
        Iimm: 0xA
------------------------------------------------
Instr. VA: 0x402386
RAW bytes (hex): 75 D4
Instr. length: 2

Instr. is a jump with target address: 0x40235C
Print instruction fields:
        Located Prefixes 0:

        OP: 0x75
        Iimm: 0xD4
------------------------------------------------
Instr. VA: 0x402388
RAW bytes (hex): 83 C4 14
Instr. length: 3
Print instruction fields:
        Located Prefixes 0:

        OP: 0x83
        mod_reg_rm: 0xC4
        Iimm: 0x14
------------------------------------------------
Instr. VA: 0x40238B
RAW bytes (hex): 89 F0
Instr. length: 2
Print instruction fields:
        Located Prefixes 0:

        OP: 0x89
        mod_reg_rm: 0xF0
------------------------------------------------
Instr. VA: 0x40238D
RAW bytes (hex): 5B
Instr. length: 1
Print instruction fields:
        Located Prefixes 0:

        OP: 0x5B
------------------------------------------------
Instr. VA: 0x40238E
RAW bytes (hex): 5E
Instr. length: 1
Print instruction fields:
        Located Prefixes 0:

        OP: 0x5E
------------------------------------------------
Instr. VA: 0x40238F
RAW bytes (hex): C3
Instr. length: 1
Print instruction fields:
        Located Prefixes 0:

        OP: 0xC3
------------------------------------------------
Instr. VA: 0x402390
RAW bytes (hex): BE 9C 01 00 00
Instr. length: 5
Print instruction fields:
        Located Prefixes 0:

        OP: 0xBE
        Iimm: 0x19C
------------------------------------------------
Instr. VA: 0x402395
RAW bytes (hex): 83 C4 14
Instr. length: 3
Print instruction fields:
        Located Prefixes 0:

        OP: 0x83
        mod_reg_rm: 0xC4
        Iimm: 0x14
------------------------------------------------
Instr. VA: 0x402398
RAW bytes (hex): 89 F0
Instr. length: 2
Print instruction fields:
        Located Prefixes 0:

        OP: 0x89
        mod_reg_rm: 0xF0
------------------------------------------------
Instr. VA: 0x40239A
RAW bytes (hex): 5B
Instr. length: 1
Print instruction fields:
        Located Prefixes 0:

        OP: 0x5B
------------------------------------------------
Instr. VA: 0x40239B
RAW bytes (hex): 5E
Instr. length: 1
Print instruction fields:
        Located Prefixes 0:

        OP: 0x5E
------------------------------------------------
Instr. VA: 0x40239C
RAW bytes (hex): C3
Instr. length: 1
Print instruction fields:
        Located Prefixes 0:

        OP: 0xC3
------------------------------------------------
Instr. VA: 0x40239D
RAW bytes (hex): 8D 76 00
Instr. length: 3
Print instruction fields:
        Located Prefixes 0:

        OP: 0x8D
        mod_reg_rm: 0x76
        disp (1): 0x0
------------------------------------------------
Instr. VA: 0x4023A0
RAW bytes (hex): BE 03 00 00 00
Instr. length: 5
Print instruction fields:
        Located Prefixes 0:

        OP: 0xBE
        Iimm: 0x3
------------------------------------------------
Instr. VA: 0x4023A5
RAW bytes (hex): 83 C4 14
Instr. length: 3
Print instruction fields:
        Located Prefixes 0:

        OP: 0x83
        mod_reg_rm: 0xC4
        Iimm: 0x14
------------------------------------------------
Instr. VA: 0x4023A8
RAW bytes (hex): 89 F0
Instr. length: 2
Print instruction fields:
        Located Prefixes 0:

        OP: 0x89
        mod_reg_rm: 0xF0
------------------------------------------------
Instr. VA: 0x4023AA
RAW bytes (hex): 5B
Instr. length: 1
Print instruction fields:
        Located Prefixes 0:

        OP: 0x5B
------------------------------------------------
Instr. VA: 0x4023AB
RAW bytes (hex): 5E
Instr. length: 1
Print instruction fields:
        Located Prefixes 0:

        OP: 0x5E
------------------------------------------------
Instr. VA: 0x4023AC
RAW bytes (hex): C3
Instr. length: 1
Print instruction fields:
        Located Prefixes 0:

        OP: 0xC3
------------------------------------------------

Process finished with exit code 0

Riporto anche il codice prodotto da MSVC utilizzando O2:

example1_msvc_o2.png

Snellito rispettoal precedente, e sono spariti tutti i JMP verso l'uscita dalla funzione. Da notare che la jump table è rimasta e la SUB è stata sostituita con una ADD EDX,-2.

Per mostre che accade a chi non ha mai "smanettato" molto con un debugger, riporto anche l'output di x32dbg, così potete confrontare l'output errato con quello mostrato sopra:
Dopo alla RET (fine procedura), si vede:

Codice:
00C01EE9 | 0F1F00                      | nop dword ptr ds:[eax],eax                   |
00C01EEC | C51E                        | lds ebx,fword ptr ds:[esi]                   | esi:EntryPoint
00C01EEE | C000 D7                     | rol byte ptr ds:[eax],D7                     |
00C01EF1 | 1E                          | push ds                                      |
00C01EF2 | C000 CE                     | rol byte ptr ds:[eax],CE                     |
00C01EF5 | 1E                          | push ds                                      |
00C01EF6 | C000 E0                     | rol byte ptr ds:[eax],E0                     |
00C01EF9 | 1E                          | push ds                                      |
00C01EFA | C000 B3                     | rol byte ptr ds:[eax],B3                     |
00C01EFD | 1E                          | push ds                                      |
00C01EFE | C000 00                     | rol byte ptr ds:[eax],0                      |
00C01F01 | 010404                      | add dword ptr ss:[esp+eax],eax               |
00C01F04 | 04 04                       | add al,4                                     |
00C01F06 | 04 04                       | add al,4                                     |
00C01F08 | 020404                      | add al,byte ptr ss:[esp+eax]                 |
00C01F0B | 04 04                       | add al,4                                     |
00C01F0D | 04 04                       | add al,4                                     |
00C01F0F | 04 04                       | add al,4                                     |
00C01F11 | 04 04                       | add al,4                                     |
00C01F13 | 04 04                       | add al,4                                     |
00C01F15 | 04 04                       | add al,4                                     |
00C01F17 | 04 04                       | add al,4                                     |
00C01F19 | 04 04                       | add al,4                                     |
00C01F1B | 04 04                       | add al,4                                     |
00C01F1D | 04 04                       | add al,4                                     |
00C01F1F | 04 04                       | add al,4                                     |
00C01F21 | 04 04                       | add al,4                                     |
00C01F23 | 04 04                       | add al,4                                     |
00C01F25 | 04 04                       | add al,4                                     |
00C01F27 | 04 04                       | add al,4                                     |
00C01F29 | 04 04                       | add al,4                                     |
00C01F2B | 04 04                       | add al,4                                     |

In questo caso il debugger rileva questo blocco come istruzioni e non come dati; gli si dovrebbe quindi dire di trattarli come DWORD e sotto come BYTE (ADD AL, 4 sono i valori visti in precedenza).
Per completezza sotto spoiler lascio anche il disassemblato di IDA Free:
Codice:
.text:00401E70 sub_401E70      proc near               ; DATA XREF: sub_401010+17↑o
.text:00401E70                                         ; sub_401010+28↑o ...
.text:00401E70
.text:00401E70 arg_0           = dword ptr  4
.text:00401E70
.text:00401E70                 push    ebx
.text:00401E71                 push    esi
.text:00401E72                 push    edi
.text:00401E73                 push    offset aExample1 ; "example1"
.text:00401E78                 call    sub_4015E0
.text:00401E7D                 mov     ebx, [esp+10h+arg_0]
.text:00401E81                 add     esp, 4
.text:00401E84                 xor     esi, esi
.text:00401E86                 mov     edi, 1
.text:00401E8B                 nop     dword ptr [eax+eax+00h]
.text:00401E90
.text:00401E90 loc_401E90:                             ; CODE XREF: sub_401E70+4D↓j
.text:00401E90                 mov     ecx, edi
.text:00401E92                 cmp     edi, ebx
.text:00401E94                 jge     short loc_401EB9
.text:00401E96                 mov     eax, ebx
.text:00401E98                 cdq
.text:00401E99                 idiv    edi
.text:00401E9B                 add     edx, 0FFFFFFFEh
.text:00401E9E                 xchg    ax, ax
.text:00401EA0
.text:00401EA0 loc_401EA0:                             ; CODE XREF: sub_401E70+47↓j
.text:00401EA0                 cmp     edx, 60h        ; switch 97 cases
.text:00401EA3                 ja      short def_401EAC ; jumptable 00401EAC default case, cases 2-7,9-95
.text:00401EA5                 movzx   eax, ds:byte_401F00[edx]
.text:00401EAC                 jmp     ds:jpt_401EAC[eax*4] ; switch jump
.text:00401EB3 ; ---------------------------------------------------------------------------
.text:00401EB3
.text:00401EB3 def_401EAC:                             ; CODE XREF: sub_401E70+33↑j
.text:00401EB3                                         ; sub_401E70+3C↑j
.text:00401EB3                                         ; DATA XREF: ...
.text:00401EB3                 inc     ecx             ; jumptable 00401EAC default case, cases 2-7,9-95
.text:00401EB4                 inc     esi
.text:00401EB5                 cmp     ecx, ebx
.text:00401EB7                 jl      short loc_401EA0
.text:00401EB9
.text:00401EB9 loc_401EB9:                             ; CODE XREF: sub_401E70+24↑j
.text:00401EB9                 inc     edi
.text:00401EBA                 cmp     edi, 0Ah
.text:00401EBD                 jl      short loc_401E90
.text:00401EBF                 pop     edi
.text:00401EC0                 mov     eax, esi
.text:00401EC2                 pop     esi
.text:00401EC3                 pop     ebx
.text:00401EC4                 retn
.text:00401EC5 ; ---------------------------------------------------------------------------
.text:00401EC5
.text:00401EC5 loc_401EC5:                             ; CODE XREF: sub_401E70+3C↑j
.text:00401EC5                                         ; DATA XREF: .text:jpt_401EAC↓o
.text:00401EC5                 pop     edi             ; jumptable 00401EAC case 0
.text:00401EC6                 pop     esi
.text:00401EC7                 mov     eax, 3
.text:00401ECC                 pop     ebx
.text:00401ECD                 retn
.text:00401ECE ; ---------------------------------------------------------------------------
.text:00401ECE
.text:00401ECE loc_401ECE:                             ; CODE XREF: sub_401E70+3C↑j
.text:00401ECE                                         ; DATA XREF: .text:jpt_401EAC↓o
.text:00401ECE                 pop     edi             ; jumptable 00401EAC case 8
.text:00401ECF                 pop     esi
.text:00401ED0                 mov     eax, 17h
.text:00401ED5                 pop     ebx
.text:00401ED6                 retn
.text:00401ED7 ; ---------------------------------------------------------------------------
.text:00401ED7
.text:00401ED7 loc_401ED7:                             ; CODE XREF: sub_401E70+3C↑j
.text:00401ED7                                         ; DATA XREF: .text:jpt_401EAC↓o
.text:00401ED7                 pop     edi             ; jumptable 00401EAC case 1
.text:00401ED8                 pop     esi
.text:00401ED9                 mov     eax, 19Ch
.text:00401EDE                 pop     ebx
.text:00401EDF                 retn
.text:00401EE0 ; ---------------------------------------------------------------------------
.text:00401EE0
.text:00401EE0 loc_401EE0:                             ; CODE XREF: sub_401E70+3C↑j
.text:00401EE0                                         ; DATA XREF: .text:jpt_401EAC↓o
.text:00401EE0                 pop     edi             ; jumptable 00401EAC case 96
.text:00401EE1                 pop     esi
.text:00401EE2                 mov     eax, 20h ; ' '
.text:00401EE7                 pop     ebx
.text:00401EE8                 retn
.text:00401EE8 sub_401E70      endp
.text:00401EE8
.text:00401EE8 ; ---------------------------------------------------------------------------
.text:00401EE9                 align 4
.text:00401EEC jpt_401EAC      dd offset loc_401EC5    ; DATA XREF: sub_401E70+3C↑r
.text:00401EEC                 dd offset loc_401ED7    ; jump table for switch statement
.text:00401EEC                 dd offset loc_401ECE
.text:00401EEC                 dd offset loc_401EE0
.text:00401EEC                 dd offset def_401EAC
.text:00401F00 byte_401F00     db      0,     1,     4,     4
.text:00401F00                                         ; DATA XREF: sub_401E70+35↑r
.text:00401F00                 db      4,     4,     4,     4 ; indirect table for switch statement
.text:00401F00                 db      2,     4,     4,     4
.text:00401F00                 db      4,     4,     4,     4
.text:00401F00                 db      4,     4,     4,     4
.text:00401F00                 db      4,     4,     4,     4
.text:00401F00                 db      4,     4,     4,     4
.text:00401F00                 db      4,     4,     4,     4
.text:00401F00                 db      4,     4,     4,     4
.text:00401F00                 db      4,     4,     4,     4
.text:00401F00                 db      4,     4,     4,     4
.text:00401F00                 db      4,     4,     4,     4
.text:00401F00                 db      4,     4,     4,     4
.text:00401F00                 db      4,     4,     4,     4
.text:00401F00                 db      4,     4,     4,     4
.text:00401F00                 db      4,     4,     4,     4
.text:00401F00                 db      4,     4,     4,     4
.text:00401F00                 db      4,     4,     4,     4
.text:00401F00                 db      4,     4,     4,     4
.text:00401F00                 db      4,     4,     4,     4
.text:00401F00                 db      4,     4,     4,     4
.text:00401F00                 db      4,     4,     4,     4
.text:00401F00                 db      4,     4,     4,     4
.text:00401F00                 db      4,     4,     4,     4
.text:00401F00                 db      3

5. Conclusione​

Ciò detto, spero sia stato di vostro interesse, non solo la parte dedicata alla mia libreria e alla funzionalità implementata, ma l'intero paragrafo 4 in particolare.
Grazie per la lettura, e se vedete qualcosa di non chiaro (o volete chiarimenti/info o correggermi in qualche parte), scrivete pure qui sotto.
 
Non avevo fatto il "push" del codice sul repository, ma è ovviamente tutto pubblico.

queue.c è la coda che memorizza i futuri VA e che viene popolata con i "salti condizionali" o con l'indirizzo successivo a un JMP. Viene letta quando viene raggiunto una foglia nell'albero (detta in altri termini: quando viene raggiunta quella che è identificata come il termine della procedura, quindi RET/INT 3, al momento).

vector.c è usata per memorizzare tutti gli indirizzi visitati, così da non ripercorrerli due volte.

function_length.c è il file il cui contenuto è presente nell'articolo. La prima procedura chiamata è alla linea 81; avviene subito la chiamata alla procedura che percorre tutti i vari path della funzione.
Al termine uso il vettore degli indirizzi visitati per stabilire l'indirizzo minore e quello maggiore, così da ottenere il nr. di bytes che determina la lunghezza del codice macchina analizzato.
 
Pubblicità
Pubblicità
Indietro
Top