使用 IDA 和 windbg 调试 LNK1123 转换到 COFF 期间失败:文件无效或损坏(中)
原总结排错process monitorvsIDAwindbg调试rcCVT1101LNK1123
前言
在 上一篇文章 中,我们总结了使用 windbg
和 IDA
找出 cvtres.exe
几个值得深究的问题
- 为什么链接的时候需要调用 cvtres.exe 呢?
微软官方描述 摘录如下:
You can specify a .res file when linking a program. The .res file is created by the resource compiler (RC). LINK automatically converts .res files to COFF. The CVTRES.exe tool must be in the same directory as LINK.exe or in a directory specified in the PATH environment variable.
- stackoverflow 上有一个更加详细的描述,摘录如下:
Input files must have the Common Object File Format (COFF) format. If an input file is not COFF, the linker automatically tries to convert 32-bit OMF objects to COFF, or runs CVTRES.EXE to convert resource files. This message indicates that the linker could not convert the file. This can also occur when using an incompatible version of CVTRES.EXE from another installation of Visual Studio, the Windows Development Kit, or .NET Framework.
- 有没有更好的设置条件断点的方式?目前的语法实在是太难用了。
可以使用
dx
- 提供的语法来设置条件断点。先定义一个辅助函数
@$get_wfs_open_file_param
- 用来获取
file
dx @$get_wfs_open_file_param = (esp_value => ((wchar_t*)*((int*)esp_value+1)).ToDisplayString("sub"))
设置条件断点
bp /w "@$get_wfs_open_file_param(@esp).EndsWith(\"510.res\")" MSVCR120!_wfsopen
是不是比传统的方式好理解的多?如果不想定义辅助函数,可以直接像下面这样设置条件断点。
bp /w "((wchar_t*)*((int*)@esp+1)).ToDisplayString(\"sub\").EndsWith(\"510.res\")" MSVCR120!_wfsopen
有什么简单的办法可以查看 __piob
- 在前一篇文章中,只是通过逻辑推理确定了当尝试打开
510.res
- 时,
__piob
- 数组中的每个元素都被占用了。并没有实际查看其内容。其实,可以通过
dx
- 命令非常方便的查看想要查看的内容。比如,可以只查看那些可用的记录项(值为
NULL
- 或者不满足
inuse()
- 和
str_locked()
- 为了让代码更容易理解,定义了几个辅助变量及函数。
$$ 以下变量定义在 VC\crt\src\stdio.h 中
dx @$ioReadFlag = 0x1
dx @$ioWriteFlag = 0x2
dx @$ioRWFlag = 0x80
dx @$ioLockedFlag = 0x8000
$$ inuse() 和 str_locked() 定义在 VC\crt\src\file2.h 中
dx -r0 @$IsInUse = (f => f->_flag & (@$ioReadFlag | @$ioWriteFlag | @$ioRWFlag))
dx -r0 @$IsLocked = (f => f->_flag & @$ioLockedFlag)
$$ 使用自定义变量 my_piob 指向 __piob
dx -r0 @$my_piob = (FILE*[512])MSVCR120!__piob
$$ 找到所有可用的记录的数量
dx @$my_piob.Where(f => f == 0 || (@$IsInUse(f) && @$IsLocked(f) ) ).Count()
$$ 找到所有不可用的记录的数量
dx @$my_piob.Where(f => !(f == 0 || (@$IsInUse(f) && @$IsLocked(f) ) ) ).Count()
当打开 510.res
为什么在打开 510.res
- 猜测应该是已经打开了一些文件。为了验证这个猜测,再次调试。
当
cvtres.exe
- 中断到
windbg
- 后,执行
x MSVCR120!__piob
- 查看
__piob
可以看到此时 __piob
的地址是 0x6250fe00
,值是 0
。说明此时还没被赋值。通过 ba w4 0x6250fe00
设置内存写断点设置好后,执行 g
命令恢复运行。几乎立刻中断到 windbg
可以看到 __piob
会在 __initstdio()
函数中被初始化。而且前 _IOB_ENTRIES
项(值为 20
)的值会被 _iob
中对应的值赋值。而 _iob
所以,cvtres.exe
最多只能通过 _wfsopen()
函数打开 512-3 = 509
个文件。也就是说,只能打开 1.res ~ 509.res
,打开 510.res
注意: _iob 的前三项分别指向了 stdin, stdout, stderror。我是怎么知道的?看代码呗。除了通过
_iob
初始化代码的注释可以看出来前三项的意义,也可以通过
stdio.h
More
还有一个小问题没解决 —— 为什么设置 PATH
环境变量后,直接通过文件名启动程序,windbg
总结
- 命令行程序默认会打开三个文件
stdin、stdout、stderror
- 。所以,
crt
- 默认能同时打开的文件数是
509
dx
参考资料
https://docs.microsoft.com/en-us/cpp/build/reference/dot-res-files-as-linker-input?view=msvc-170
https://stackoverflow.com/questions/61581826/visual-studio-2019-cvt1101-lnk1123-fatal-error
vs2013
自带的 crt
欢迎各位小伙伴指出不足,提出建议!感谢关注我的博客:)
作 者:编程难
码云博客:https://bianchengnan.gitee.io
github博客:https://bianchengnan.github.io
版权所有,转载请保留原文链接:)