2009-05-04 6 views
3

Est-il possible d'accéder (en lecture seule) à n'importe quel emplacement de mémoire arbitraire sans courir dans une violation d'accès? Je pensais que chaque processus a son propre espace d'adresse virtuelle et qu'il peut lire tous les emplacements de mémoire disponibles ... ne semble pas être le cas, étant donné que mon programme se bloque si je fais quelque chose commeLecture d'emplacements de mémoire arbitraires? Possible?

var 
    IntPtr : PInteger; 
    AnInteger : Integer; 
... 
IntPtr := $100; 
AnInteger := IntPtr^; 

Je suis toujours essayer d'écrire ma fonction de taille récursive de bas niveau et essayer de détecter si un membre de données est une référence d'objet ou non.

Merci!

+0

Je sens dans votre code de nombreux pointeurs. Les pointeurs sont le chemin vers le côté obscur. Les pointeurs mènent à des violations d'accès, les violations d'accès entraînent des pannes de programme et les plantages de programmes entraînent des clients mécontents. –

+0

Salut! Je n'utilise pas souvent de pointeurs très souvent (en Delphi au moins). Mais dans ce cas, je voulais détecter si une pièce de 4 octets d'un objet est une référence d'objet - et pour cela je dois descendre au niveau du pointeur ... – jpfollenius

Répondre

5

Vous pouvez uniquement accéder à la mémoire de votre propre processus via des pointeurs, et même dans ce cas, seules les parties ont été mappées pour votre processus. Il y a des hooks de débogueur qui vous donneront accès à la mémoire des autres processus; mais ils sont difficiles à corriger.

Donc, si vous voulez vraiment itérer votre mémoire, vous pouvez probablement trouver les fonctions dont vous avez besoin ici processus: http://msdn.microsoft.com/en-us/library/ms878234.aspx

AFAIR dans les fenêtres également partie du noyau est mis en correspondance avec vos processus d'espace mémoire (qui est le raison de ne pas avoir tout le 4G disponible pour votre processus).

1

À moins qu'il y ait un moyen magique que je ne connais pas, je suis sûr que vous ne pouvez pas faire cela. Windows utilise de la mémoire protégée, ce qui signifie que vous ne pouvez pas accéder à tout ce qui ne vous a pas été spécifiquement affecté.

Il existe un DMA, mais il est réservé aux logiciels de niveau pilote.

+0

DMA n'a rien à voir avec ça, c'est pour le transfert de données entre les périphériques et la mémoire sans forcer le CPU. –

2

La mémoire peut ne pas être mappée à toutes les adresses. Et les 4 kb inférieurs sont toujours protégés.

Toutefois, si c'est pour les machines virtuelles, si vous contrôlez le gestionnaire de mémoire, vous pouvez créer une liste avec toutes les plages de mémoire que votre application a mappées.

4

Votre application se bloque? Il y a quelque chose qui ne va pas dans votre application. Habituellement, il y aura un AV simple. Une AV entraîne un message d'erreur. C'est tout.

BTW, vous ne devriez pas avoir peur de - il suffit de le gérer.

function IsValidObject(const AObj: Pointer { or TObject}): Boolean; 
begin 
    try 
    ... 
    // place your checking code there 
    Result := ...; 
    except 
    on EAccessViolation do 
     Result := False; 
    end; 
end; 

La seule exception à cette règle qui vient à l'esprit est si vous écrivez une sorte de gestionnaire d'exceptions et que vous voulez détecter s'il y a un objet valide. Dans ce cas, vous ne voulez probablement pas générer une exception dans le gestionnaire d'exception;)

Si tel est votre cas - essayez d'utiliser ce code (ceci est un exemple):

function GetReadableSize(const AAddress: Pointer; const ASize: Cardinal): Cardinal; 
const 
    ReadAttributes = [PAGE_READONLY, PAGE_READWRITE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE]; 
var 
    MemInfo: TMemoryBasicInformation; 
    Tmp: Cardinal; 
begin 
    Result := 0; 
    if (VirtualQuery(AAddress, MemInfo, SizeOf(MemInfo)) = SizeOf(MemInfo)) and 
    (MemInfo.State = MEM_COMMIT) and (MemInfo.Protect in ReadAttributes) then 
    begin 
    Result := (MemInfo.RegionSize - (Cardinal(AAddress) - Cardinal(MemInfo.BaseAddress))); 
    if Result < ASize then 
    begin 
     repeat 
     Tmp := GetReadableSize(Pointer(DWord(MemInfo.BaseAddress) + MemInfo.RegionSize), (ASize - Result)); 
     if (Tmp > 0) then 
      Inc(Result, Tmp) 
     else 
      Result := 0; 
     until (Result >= ASize) or (Tmp = 0); 
    end; 
    end; 
end; 

function IsValidBlockAddr(const AAddress: Pointer; const ASize: Cardinal): Boolean; 
begin 
    Result := (GetReadableSize(AAddress, ASize) >= ASize); 
end; 

Mais généralement, vous devriez préférer la première approche.

+0

J'ai besoin de temps pour regarder de plus près votre deuxième exemple de code, mais une note: je ne reçois pas une violation d'accès (vous avez raison), mais l'opération déréférencer le pointeur prend une éternité. C'est comme quand je déréférence un pointeur nul ... – jpfollenius

+0

Je pense que vous voyez quelque chose d'autre :(Le hang à IntPtr^semble TRÈS étrange Utilisez-vous des crochets d'exception? Peut-être votre pile a été corrompue? – Alex

1

Dans l'ancien Windows 95, 98, Me, vous pouviez faire un certain nombre d'asm inline dans votre fonction et lire/écrire un emplacement de mémoire arbitraire ou un port matériel ...

Fonction ReadPortByte: Octet; var Socle: Mot; begin Base: = F Adresse; asm mov DX, base dans AL, DX mov Résultat, AL fin; fin;

Vous pouvez toujours le faire en utilisant un pilote de périphérique, mais Vista peut vous causer quelques problèmes à moins que le pilote soit compilé correctement pour Vista et au-dessus.

Il en existe plusieurs gratuits et valent la peine d'être testés.

John

3

Si vous voulez essayer en toute sécurité à lire une adresse mémoire sans chichi, et obtenir un beau code d'erreur plutôt que d'une exception lorsque la mémoire que vous essayez de lire est inaccessible, la fonction que vous voulez à utiliser est dans le WinAPI: ReadProcessMemory.

Questions connexes