简体   繁体   English

是否可以检查内存地址是否有效?

[英]Is it possible to check if a memory address is valid?

A client came to me with an application that they lost the source code to.一位客户带着他们丢失了源代码的应用程序来找我。 This application is crashing seemingly at random, when loading some files.加载某些文件时,此应用程序似乎随机崩溃。 I suspect that the issue is due to a race condition in which a pointer is deleted and then either not set to NULL or not checked for validity.我怀疑这个问题是由于竞争条件造成的,其中一个指针被删除,然后要么没有设置为 NULL,要么没有检查有效性。

When stepping through the assembly using OllyDBG, I found that the crash ALWAYS happens at the same location, so this is kind of re-enforcing my theory.当使用 OllyDBG 逐步完成程序集时,我发现崩溃总是发生在同一个位置,所以这有点强化我的理论。 This is the assembly line it sometimes crashes on, keyword sometimes.这是它有时崩溃的装配线,有时是关键字。

MOV EDI,DWORD PTR DS:[EAX]

Is it possible to validate a memory address is valid and exists either through native assembly or through C++ that pulls an address through an inline assembly call (or something like this)?是否可以通过本机汇编或通过内联汇编调用(或类似的东西)提取地址的 C++ 来验证内存地址是否有效并且存在?

There is no general standard way in C++ to validate a memory address. C++ 中没有通用的标准方法来验证内存地址。 Nor is there such assembly instruction that I know of.也没有我所知道的这样的组装说明。

On a memory mapped system (such as any modern operating system), you may be able to check whether an address has been mapped for the process using a system specific API.在内存映射系统(例如任何现代操作系统)上,您可以使用系统特定的 API 检查是否已为进程映射地址。 An address being mapped to the process doesn't guarantee that the address is valid from the C++ point of view, but an unmapped address is definitely invalid.从 C++ 的角度来看,映射到进程的地址并不能保证该地址有效,但未映射的地址肯定是无效的。

Furthermore, even if could find that an address is valid, that doesn't tell you whether the object you are expecting is in that address or something else.此外,即使可以发现一个地址是有效的,也不能告诉您您期望的对象是在该地址中还是在其他地方。


There are tools for validating memory accesses outside of the C++ language 1 .在 C++ 语言1之外,还有一些用于验证内存访问的工具。 There's for example Valgrind and also compiles provide address sanitisers and memory sanitisers.例如 Valgrind 和编译器提供地址清理器和内存清理器。 Mostly, these help detect invalid accesses that wouldn't have crashed the program otherwise.大多数情况下,这些有助于检测不会导致程序崩溃的无效访问。 But they also often can provide additional information regarding that memory.但它们通常也可以提供有关该内存的附加信息。

1 If you had access to the source. 1如果您有权访问源。

I suspect that the issue is due to a race condition我怀疑这个问题是由于比赛条件造成的

Being able to validate a memory address won't solve this problem.能够验证内存地址并不能解决这个问题。 What you should do 1 , is to use a debugger to find out what object is being accessed, find all places where that object is accessed.您应该做的1是使用调试器找出正在访问的对象,找到访问该对象的所有位置。 If any of those places is not holding a mutex that is common to all other places potentially accessing the object at the same time, then there's your bug.如果这些地方中的任何一个没有持有可能同时访问该对象的所有其他地方共有的互斥锁,那么这就是你的错误。

1 If you had access to the source. 1如果您有权访问源。

lost the source code丢失了源代码

If you have a massive budget, then you could try reverse-engineering it and try to figure out what it's doing.如果您有大量预算,那么您可以尝试对其进行逆向工程并尝试弄清楚它在做什么。 I wouldn't hold my breath;我不会屏住呼吸; it may be best to declare this as a lost cause.最好将其宣布为失败的原因。

Everyone provided some great responses.每个人都提供了一些很好的回应。 Unfortunately, in this situation, the client wasn't willing to pay to have the software re-developed entirely.不幸的是,在这种情况下,客户不愿意为软件的完全重新开发付费。

I managed to kind of negate the crash... After identifying exactly where the crash occurred I used used code injection to JMP to a custom C++ function.我设法否定了崩溃......在确定崩溃发生的确切位置后,我使用了将代码注入到 JMP 到自定义 C++ 函数。 The C++ function employs a __try __except block. C++ 函数使用 __try __except 块。 Inside of the Try I placed the problem assembly code, and if the problem code causes a crash, the __except catches it.在 Try 我放置了问题汇编代码,如果问题代码导致崩溃,__except 会捕获它。 After that, it was just a matter of analyzing what the problem code was doing and when it started doing something else and then jumping to the start of that "something else" part of the problem function when an exception is caught.之后,只需分析问题代码在做什么以及何时开始执行其他操作,然后在捕获异常时跳转到问题函数的“其他”部分的开头。

It's not exactly detecting if a memory location is valid or not, but rather it's just skipping code if it causes an exception.它并不能准确地检测内存位置是否有效,而只是在导致异常时跳过代码。 Hope this helps someone eventually...希望这最终对某人有所帮助...

Yes, validating a pointer's content is possible.是的,可以验证指针的内容。 However, verifying that the target is the correct one is more difficult.但是,验证目标是否正确则比较困难。

In order to validate a pointer you'll need:为了验证指针,您需要:

  1. Table of valid address ranges (addresses that are implemented and their ranges).有效地址范围表(实现的地址及其范围)。
    For example, on embedded systems addresses that are decoded may not have memory or devices at all locations.例如,在嵌入式系统上,解码的地址可能并非在所有位置都有内存或设备。
  2. For OS's that support paging or virtual memory, you'll need to figure out the limits of your program's memory area (as given by the OS).对于支持分页或虚拟内存的操作系统,您需要弄清楚程序内存区域的限制(由操作系统给出)。 The OS may take portions of your executable and swap them out with code on a hard drive.操作系统可能会占用您的可执行文件的一部分并将它们与硬盘驱动器上的代码交换。
  3. For OS's that support virtual memory, you'll have to figure out where in the "virtual" memory that your pointer is allowed to access.对于支持虚拟内存的操作系统,您必须确定允许指针访问的“虚拟”内存中的哪个位置。 Read about memory mapped files.阅读有关内存映射文件的信息。
  4. On some platforms, the address 0x0000 is a valid address.在某些平台上,地址 0x0000 是有效地址。 Verify if this is the case on your target platform.验证您的目标平台上是否存在这种情况。

IMHO, pointer content can be validated, but the validation may be very compilicated.恕我直言,可以验证指针内容,但验证可能非常复杂。

Prefer to use references.更喜欢使用引用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM