2015-11-19 5 views
5

Recentemente, in this question, ho chiesto come ottenere un indirizzo di memoria raw di classe in C# (è un rozzo hack inaffidabile e una cattiva pratica, non usarlo a meno che non ne abbia davvero bisogno). Sono riuscito, ma poi è sorto un problema: secondo l'articolo this, le prime 2 parole nella rappresentazione della memoria grezza della classe dovrebbero essere puntatori alle strutture SyncBlock e RTTI e quindi l'indirizzo del primo campo deve essere sfalsato di 2 parole [8 byte in sistemi a 32 bit, 16 byte in sistemi a 64 bit] dall'inizio. Tuttavia, quando eseguo il dump dei primi byte dalla memoria nella posizione dell'oggetto, l'offset grezzo del primo campo dall'indirizzo dell'oggetto è solo 1 parola a 32 bit (4 byte), che non ha alcun senso per entrambi i tipi di sistemi . Dalla domanda che ho collegato:Quali sono il layout e le dimensioni dell'intestazione di una classe gestita nella memoria non gestita?

class Program 
{ 
    // Here is the function. 
    // I suggest looking at the original question's solution, as it is 
    // more reliable. 
    static IntPtr getPointerToObject(Object unmanagedObject) 
    { 
     GCHandle gcHandle = GCHandle.Alloc(unmanagedObject, GCHandleType.WeakTrackResurrection); 
     IntPtr thePointer = Marshal.ReadIntPtr(GCHandle.ToIntPtr(gcHandle)); 
     gcHandle.Free(); 
     return thePointer; 
    } 
    class TestClass 
    { 
     uint a = 0xDEADBEEF; 
    } 
    static void Main(string[] args) 
    { 
     byte[] cls = new byte[16]; 

     var test = new TestClass(); 

     var thePointer = getPointerToObject(test); 
     Marshal.Copy(thePointer, cls, 0, 16); //Dump first 16 bytes... 
     Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes(thePointer.ToInt32()))); 
     Console.WriteLine(BitConverter.ToString(cls)); 

     Console.ReadLine(); 

     gcHandle.Free(); 
    } 
} 
/* Example output (yours should be different): 
40-23-CA-02 
4C-38-04-01-EF-BE-AD-DE-00-00-00-80-B4-21-50-73 

That field's value is "EF-BE-AD-DE", 0xDEADBEEF as it is stored in memory. Yay, we found it! 
*/ 

Perché è così? Forse ho sbagliato l'indirizzo, ma come e perché? E se non l'avessi fatto, cosa potrebbe esserci di sbagliato comunque? Forse, se quell'articolo è sbagliato, ho semplicemente frainteso l'aspetto dell'intestazione di classe gestita? O forse non ha quel puntatore di blocco - ma perché e come è possibile? ..

(Queste sono, ovviamente, solo alcune opzioni possibili, e, mentre sto ancora andando a controllare attentamente ciascuna Posso prevedere che l'ipotesi selvaggia non può essere paragonata in termini di tempo e accuratezza a una risposta corretta)

+1

Il puntatore dell'oggetto punta al secondo campo nell'intestazione dell'oggetto. Un trucco per mantenere il codice macchina più compatto, è quello che è più probabile che venga utilizzato. Tieni presente che il codice è drasticamente sbagliato, viene generato un disastro quando il garbage collector viene eseguito dopo la chiamata getPtrToObject(). Probabilità basse, non zero. Appuntare è un requisito difficile. –

+0

@HansPassant L'indice SyncRoot non dovrebbe essere in offset -4? –

+0

Sì, il primo campo è quindi un indice negativo. –

risposta

0

@HansPassant ha evidenziato brillantemente che il puntatore dell'oggetto in questione punta alla struttura seconda, la tabella dei metodi. Ora questo è assolutamente logico per motivi di prestazioni, dato che la tabella dei metodi (struttura RTTI) è usata molto più spesso della struttura SyncRoot, che, quindi, si trova ancora prima dell'indice negativo -1. Ha chiarito che non vuole pubblicare questa risposta, quindi la pubblicherò da sola, ma il merito va comunque a lui.

Ma vorrei ricordare che questa è una sporca inaffidabile mod , possibilmente rendendo il sistema instabile:

Al di là del problema pinning, altre questioni cattivi non stanno avendo idea di quanto tempo l'oggetto è e come sono disposti i campi.

Si consiglia di utilizzare il debugger, invece, a meno che non si capisce tutte le conseguenze, capire esattamente che cosa si sta cercando di fare e realmente bisogno di farlo - di utilizzare questo, sporca e inaffidabile, modo.