背景

我们知道,任何应用程序都是运行于操作系统之上,所以必须依赖于操作系统。Windows操作系统有如此多的版本,某些老版本的应用程序可能在新版本的操作系统中无法运行。为了新版本操作系统兼容旧版本的应用程序,Microsoft开发了一套兼容体制。

实现

那么Windows怎么实现旧版本应用程序的兼容的呢?从两个方面来讲:UI层面与技术层面。

  • UI层面

每个可执行程序右键属性都会有一页兼容性属性页,该页中可设置不同的兼容属性。




tispark兼容性 兼容性运行_windows


主要就是设置兼容模式,可以选择具体的兼容操作系统版本。

  • 技术层面

旧版本程序无法在新版本操作系统中使用,主要是由于某些API在不可用或者不兼容。所以为了兼容旧版本程序,Windows采用hook api的方式,对系统API进行hook,使应用程序能调用就把本API。

问题

某程序一直运行正常,突然已启动就崩溃,程序崩溃的地方为入口函数被修改,程序执行到不可访问的内存位置。通过使用ProcessMonitor过滤进程行为,发现修改入口函数地址的模块为AcGenral.dll。

正常的程序启动后不会加载该dll,再次使用ProcessMonitor过滤进程行为,观察加载AcGenral.dll的调用栈,发现与ShimEng模块,该模块与操作系统兼容有关。怀疑设置了EXE可执行程序的兼容属性,打开EXE属性,查看兼容属性,并未发现有设置任何选项。无奈只能再次过滤进程行为,最终确定会读区注册表位置:HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers。

查看对应注册表,发现里面存有对应的EXE路径,也就是EXE被加入到兼容列表中。对应的兼容属性为~ignorefreelibary($dll),初步判断为EXE退出时释放dll有问题,内存泄漏或者崩溃导致,被Windows操作系统加入到兼容名单中。一旦加入,就会加载hook api的dll,调用API发生变化导致程序异常。

经以上方法排查,解决方案也很简单,删除注册表即可。再次启动程序正常运行,也不在加载AcGenral.dll。