首页 > 其他分享 >使用 IDA 和 windbg 调试 LNK1123 转换到 COFF 期间失败:文件无效或损坏(下)

使用 IDA 和 windbg 调试 LNK1123 转换到 COFF 期间失败:文件无效或损坏(下)

时间:2022-12-20 22:07:35浏览次数:79  
标签:exe windbg -- cvtres process PATH LNK1123 COFF

使用 IDA 和 windbg 调试 LNK1123 转换到 COFF 期间失败:文件无效或损坏(下)

原总结排错process monitorvsIDAwindbg调试rcCVT1101LNK1123

前言

在前面两篇文章中(​​这里​​​,​​这里​​​)总结了使用 ​​windbg​​ 和 ​​IDA​​ 找出 ​​cvtres.exe​​ 报错的根本原因,并把一些细节问题弄清楚了。但是还剩下一个小细节没有深究 —— 如果启动 ​​cvtres.exe​​ 的时候没有指定全路径,​​windbg​

说明: 写完本文,我犹豫了很久要不要发表出来。因为这个问题其实很简单(在设置 PATH 环境变量时,路径多加了双引号)。但是当时的我真的是当局者迷,完全没意识到这个问题,导致花费了很长时间。process monitor,gflag,IDA,windbg,轮番上场,甚至都调试起 windbg 来了(嗯,你没看错,不是用 windbg 调试,而是调试 windbg),好一阵忙活,中间还走了很多弯路(自以为是的在错误的函数中下断)。最后幡然醒悟,原来真理就在那躺着,静静的等着被发现。

之所以决定发出来有几点原因:

  1. 介绍了让进程自动中断到调试器中的方法,甚至是让一个调试器自动中断到另外一个调试器中的方法。
  2. 介绍了只对特定线程设置断点的方法、使用

wt

  1. 提醒自己,在调试过程中一定要保持清醒的头脑。

没耐心的朋友直接跳到最后即可。

问题回顾

相信小伙伴儿们都已经知道可以通过 ​​gflags​​ 设置 ​​Image File Execution Option​​ 来让指定程序启动时自动中断到调试器。但是当启动 ​​cvtres.exe​​ 的时候,如果只指定文件名,​​windbg​

使用 IDA 和 windbg 调试 LNK1123 转换到 COFF 期间失败:文件无效或损坏(下)_调试器

windbg-cannot-start-cvtres-error

猜测应该是 ​​windbg​​我依稀记得创建进程时,​​CreateProcess()​​ 会到 ​​PATH​​ 环境变量指定的路径中查找文件。所以我在脚本开始的地方把 ​​cvtres.exe​​ 所在的路径添加到 ​​PATH​​ 环境变量。使用 ​​process explorer​​ 查看 ​​windbg​​ 对应的 ​​PATH​​ 环境变量的值,发现 ​​PATH​​ 环境变量已经包含了 ​​cvtres.exe​​ 所在的路径。因为 ​​PATH​

使用 IDA 和 windbg 调试 LNK1123 转换到 COFF 期间失败:文件无效或损坏(下)_环境变量_02

view-windbg-path-variable

提示: 注意上图中高亮部分。一切皆因它而起。

难道 ​​windbg​​ 不是通过 ​​CreateProcess()​​ 创建的新进程?看来需要调试一下 ​​windbg​​ 了。但是 ​​windbg​

螳螂捕蝉,黄雀在后

还记得我们是怎么调试 ​​cvtres.exe​​ 的吗?可以用同样的方法调试 ​​windbg​​ —— 通过 ​​gflags​​ 为 ​​windbg​​ 设置 ​​Image File Execution Option​​。但是有一个细节需要注意:​​Debugger​​​​cdb​​ 与 ​​windbg​​ 同源,大多数命令与 ​​windbg​

使用 IDA 和 windbg 调试 LNK1123 转换到 COFF 期间失败:文件无效或损坏(下)_双引号_03

use-cdb-debugging-windbg-with-gflags

按上图设置后,​​windbg.exe​​ 在启动时会自动中断到 ​​cdb.exe​​双击启动脚本,​​cvtres.exe​​ 会自动中断到 ​​windbg​​ 中,而 ​​windbg​​ 会自动中断到 ​​cdb​​ 中。下图是 ​​windbg​​ 中断到 ​​cdb​

使用 IDA 和 windbg 调试 LNK1123 转换到 COFF 期间失败:文件无效或损坏(下)_调试器_04

cdb-auto-attach-to-windbg

小提示: 可以使用 |

​windbg​

断错函数了?

创建进程应该会走 ​​CreateProcess()​​ 系列中的一个,猜测 ​​windbg​​ 应该也是调用 ​​CreateProcess()​​ 创建的子进程,与创建普通进程不同的是,​​windbg​​ 需要调试新启动的进程。当为 ​​CreateProcess()​​ 函数的 ​​dwCreationFlags​​ 参数设置一个特殊的标志位 ​​DEBUG_PROCESS​​ 时,在进程创建过程中就会建立相关的调试对象,​​windbg​​按照上面的理论,在 ​​cdb​​ 中输入 ​​x *!*CreateProcess*​​ 查看相关函数,发现了一堆相关函数。想着最终肯定会调用 ​​ntdll​​ 模块中的函数,于是在 ​​cdb​​ 中输入 ​​bp ntdll!NtCreateProcessEx​​,然后执行 ​​g​​ 命令重新运行 ​​windbg​​。 但是居然没断下来。难道 ​​windbg​​ 不是通过 ​​NtCreateProcessEx()​​ 启动新进程的吗?还是在调用 ​​NtCreateProcessEx()​

对比正常流程

通过全路径启动 ​​cvtres.exe​​ 的时候,​​windbg​​ 可以正常启动对应的程序。可以对比查看正常情况下 ​​windbg​​通过 ​​process monitor​​ 监听相关事件,只查看进程相关的事件,可以看到启动 ​​cvtres.exe​

使用 IDA 和 windbg 调试 LNK1123 转换到 COFF 期间失败:文件无效或损坏(下)_双引号_05

view-windbg-create-cvtres-call-stack

看来 ​​windbg​​ 是通过 ​​kernelbase!CreateProcessW()​​ 启动进程的,该函数内部最终会调用 ​​ntdll!NtCreateUserProcess()​​。看来,前面草率了,在错误的函数中设置了断点。赶紧在 ​​ntdll!NtCreateUserProcess()​​看来,应该是在前面就出错了。尝试在 ​​kernelbase!CreateProcessW()​

重新下断

在 ​​kernelbase!CreateProcessW()​​ 中设置断点,再次运行程序,这次终于断下来了。执行 ​​gu​​ 退出 ​​kernelbase!CreateProcessW()​​ ,然后查看返回值,也就是查看 ​​eax​​ 的值,发现 ​​eax​​ 的值是 ​​0​​,根据 ​​​msdn CreateProcess 文档​​​ 中的描述可知,返回 ​​0​​ 表示出错了。执行 ​​!gle​​ 查看错误码,发现 ​​Last Error​​ 的值是 ​​2​​,也就是 ERROR_PATH_NOT_FOUND。​​System Error Codes (0-499)​​​ 中对应的描述如下:​​The system cannot find the file specified.​​,翻译过来就是 系统找不到指定的文件,与 ​​windbg​

使用 IDA 和 windbg 调试 LNK1123 转换到 COFF 期间失败:文件无效或损坏(下)_环境变量_06

run-createprocess-and-view-return-value-and-last-error

看来问题出在 ​​kernelbase!CreateProcessW()​​ 函数内部 ,用 ​​IDA​​ 看了下 ​​kernelbase!CreateProcessW()​​ 的反汇编代码,发现该函数只是直接调用了 ​​kernelbase!CreateProcessInternalW()​​。而 ​​kernelbase!CreateProcessInternalW()​​ 的反汇编代码超级多,即使用 ​​IDA​​ 的 ​​F5​​ 得到的伪代码都非常多,实在没耐心看完。那该怎么办呢?脑子中突然想起一个很久之前就知道但是一直没真正使用过的命令 —— ​​wt​​。

wt 立功了

重新运行程序,当 ​​windbg​​ 中断到 ​​cdb​​ 后,输入 ​​bp kernelbase!CreateProcessInternalW​​ 设置好断点,输入 ​​g​​ 重新运行 ​​windbg​​。中断下来后,输入 ​​wt -l1​

提示: 因为 wt 的输出结果很可能会有很多,所以最好先执行 .logopen d:\windbg.txt 来打开日志文件,追踪完成后再执行 .logclose

查看日志文件中的调用记录,很快就发现了让我头脑瞬间清醒的几个函数调用。一个是 ​​SearchPathW​​ 一个是 ​​RtlSetLastWin32Error​​。

使用 IDA 和 windbg 调试 LNK1123 转换到 COFF 期间失败:文件无效或损坏(下)_调试器_07

view-wt-createprocessinternalw

一看到 ​​RtlSetLastWin32Error​​,瞬间清醒了。​​GetLastError​​一看到 ​​SearchPathW​​,立刻就联想到很可能是在通过 ​​PATH​​ 环境变量在找文件。后悔最开始的时候没用 ​​process monitor​​再次运行程序,使用 ​​process monitor​​ 观察一下文件访问情况。看到下图的访问记录(红色高亮的路径,居然带着双引号),我瞬间就明白了,一定是我设置的 ​​PATH​

使用 IDA 和 windbg 调试 LNK1123 转换到 COFF 期间失败:文件无效或损坏(下)_双引号_08

view-cvtres-in-process-monitor

修复

既然是指定的路径出问题了(不能带双引号),修改脚本内容如下:

set path=%path%;C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\
cvtres.exe /machine:x86 /nologo /out:"d:\test-rc-compile-error\test.tmp" /readonly 1.res 2.res 3.res 4.res 5.res

再次运行脚本,果然一切正常了。

有趣的访问方式

当我在 ​​process monitor​

使用 IDA 和 windbg 调试 LNK1123 转换到 COFF 期间失败:文件无效或损坏(下)_双引号_09

interesting-file-access-pattern

有没有发现什么规律?注意对照脚本代码看,每次访问失败后都会多取一部分再次进行尝试。

cvtres.exe /machine:x86 /nologo /out:"d:\test-rc-compile-error\test.tmp" /readonly 1.res 2.res 3.res 4.res 5.res

进一步调试确认后,上面提到的对 ​​SearchPathW​​ 的调用,并不是在对 ​​PATH​​ 环境变量中的每个路径做循环。而是在对脚本中的每个部分进行循环。​​SearchPathW​​ 会在内部处理环境变量中的值。根据 ​​​MSDN SearchPathW 的文档​​,这个函数的参数如下:

DWORD SearchPathW(
[in, optional] LPCWSTR lpPath,
[in] LPCWSTR lpFileName,
[in, optional] LPCWSTR lpExtension,
[in] DWORD nBufferLength,
[out] LPWSTR lpBuffer,
[out, optional] LPWSTR *lpFilePart
);

其中,​​PATH​​ 环境变量的值会传给 ​​lpPath​​ 参数。上面提到的有规律的调用是通过参数 ​​lpFileName​

~4 bp KERNELBASE!SearchPathW ".echo **************** bang ****************; du /cA0 poi(esp+4) LA0; du /cA0 poi(esp+8) LA0; kv2; gc;"

​~4​​ 表示只对 ​​4​​ 号线程设置断点,其它线程调用 ​​KERNELBASE!SearchPathW​​​​/cA0​​ 表示显示指定显示列宽为 ​​0xA0​​,如果不指定,则按默认列宽进行显示。​​LA0​​ 表示只显示前 ​​0xA0​

运行结果如下图:

使用 IDA 和 windbg 调试 LNK1123 转换到 COFF 期间失败:文件无效或损坏(下)_环境变量_10

auto-display-param-and-callstack

反思

其实这个问题本来应该很快就能解决的。

首先,在调试之前就应该使用 ​​process monitor​​ 查看文件访问事件。只不过当时脑子不清醒,只是用 ​​process monitor​​其次,当时陷入了思维误区 —— 想当然的认为带空格的路径一定要加上双引号。整个排查过程中都没有怀疑是多加了双引号导致的问题。反过头来看这个问题,觉得自己太傻了,查看 ​​PATH​

收获

  • 长记性了,设置

​PATH​

  • 再次熟悉了使用

​gflags​

  • 设置

​Image File Execution Option​

  • 熟悉了

​wt​

  • 的用法。很早之前就知道

​wt​

  • 熟悉了为指定线程设置断点的方法。语法很简单,很容易记忆。在

​bp​

  • 之前添加

​~tid​

  • ,即可为指定的线程设置断点。
  • 知道了突破默认输出列宽的方法 —— 通过

​/c​

  • 熟悉了

​CreateProcess​

参考资料

​https://docs.microsoft.com/zh-cn/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw​

​https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags​

​https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-​

​https://docs.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-searchpathw​

​https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/d--da--db--dc--dd--dd--df--dp--dq--du--dw--dw--dyb--dyd--display-memor​

欢迎各位小伙伴指出不足,提出建议!感谢关注我的博客:)

作 者:​​编程难​​

码云博客:​​https://bianchengnan.gitee.io​

github博客:​​https://bianchengnan.github.io​

版权所有,转载请保留原文链接:)



标签:exe,windbg,--,cvtres,process,PATH,LNK1123,COFF
From: https://blog.51cto.com/u_15469822/5956822

相关文章

  • 使用 IDA 和 windbg 调试 LNK1123 转换到 COFF 期间失败:文件无效或损坏(中)
    使用IDA和windbg调试LNK1123转换到COFF期间失败:文件无效或损坏(中)原总结排错processmonitorvsIDAwindbg调试rcCVT1101LNK1123前言在​​上一篇文章​​​中,我们......
  • 使用Windbg找出程序CPU高问题
    使用Windbg找出程序CPU高问题ReggieDing系统架构师​关注 1人赞同了该文章背景本人在把应用程序部署到服务器上运行,观察一段时间后运行平稳,CPU......
  • Windbg提示:*** WARNING: Unable to verify checksum for 的处理
    当我们用windbg调试时,经常会遇到“***WARNING:Unabletoverifychecksumforxxx.dll”这样的提示,他的意思时不能校验某某模块的校验和。这一般都是我们的动态库或exe的......
  • windbg preview下载及其历史版本下载
    WinDBG是专门针对WindowsNT系列操作系统而设计的调试器。WinDBG的最初版本是微软公司在开发最初WindowsNT操作系统(NT3.1)期间推出的,它是当时NT团队内部开发和调试NT操作系......
  • windbg 分析 32 位进程的 64 位转储文件
    场景:x86的项目在x64的windows机器上运行时出现未响应的情况,使用任务管理器创建该进程的转储文件因为项目是32位的,所以使用x86的windbg来调试dmp文件,使用kn......
  • Windbg命令大全
    Windbg是在windows平台下,强大的用户态和内核态调试工具。相比较于VisualStudio,它是一个轻量级的调试工具,所谓轻量级指的是它的安装文件大小较小,但是其调试功能,却比VS更为......
  • WinDBG详解进程初始化dll是如何加载的
    一:背景1.讲故事有朋友咨询个问题,他每次在调试WinDbg的时候,进程初始化断点之前都会有一些dll加载到进程中,比如下面这样:Microsoft(R)WindowsDebuggerVersion10.0.252......
  • windbg调试kvm windows虚机
    参考:http://m.blog.chinaunix.net/uid-22954220-id-4733247.html准备2台虚机,一台target目标机,用于运行要调试的windows系统(调试内核),一台debug调试机,用于运行windbg,配置......
  • windbg下看系统非分页内存
       这篇文章实在是闲的无聊才写的,因为快过年了...文章基于xpsp3   先看看和非分页内存相关的全局变量,也好有个大局观:kd>xnt!MmNonPaged*805517d8nt!Mm......
  • 用windbg为无效页面建立页面映射
       前几天和同事扯淡,说调试驱动时访问无效内存会蓝屏,好麻烦,应该让windbg自动建立一个有效的页面,这样就不用蓝屏重启了。虽然说这是扯淡,但仔细想想貌似也不是不可能实现......