jjzjj

c++ - `LoadLibraryExW` 从 `0xC0000023` 触发异常 `NtMapViewOfSection`

coder 2024-02-24 原文

缩小这个问题的范围真的很难,但我们开始吧。

上下文

我处于加载到主机 (TstCon.exe) 的 32 位 ActiveX 控件的上下文中。卸载并重新加载控件后,我从 NtMapViewOfSection 收到一连串错误,第一个错误发生在 odbc32.dll 使用 LoadLibraryExW 加载时C:\Windows\system32\odbcint.dll。那时,SEH 异常从 NtMapViewOfSection 内部某处发出,代码为 0xC0000023(根据调试器也称为 STATUS_BUFFER_TOO_SMALL)。

后果

这是调试器拦截异常时调用堆栈的样子:

ntdll.dll!_NtMapViewOfSection@40()
KernelBase.dll!BasepLoadLibraryAsDataFileInternal()
KernelBase.dll!BasepLoadLibraryAsDataFile()
KernelBase.dll!LoadLibraryExW()
odbc32.dll!_InitializeDll@0()
odbc32.dll!_SQLAllocEnv@4()
<OurDll>.dll!<OurFunction>()
...

那时,我已经使用非常理智的技术来检索调用NtMapViewOfSection 的参数,方法是遵循this documentation。 :

*(void**)(ESP + 4 + 0)           /*SectionHandle*/      0x000003b0              void *
*(void**)(ESP + 4 + 4)           /*ProcessHandle*/      0xffffffff              void *
*(void**)(ESP + 4 + 8)           /*BaseAddress*/        0x00daae30              void *
*(unsigned long*)(ESP + 4 + 12)  /*ZeroBits*/           0x00000000              unsigned long
*(unsigned long*)(ESP + 4 + 16)  /*CommitSize*/         0x00000000              unsigned long
*(long long**)(ESP + 4 + 20)     /*SectionOffset*/      0x00000000 {???}        __int64 *
*(unsigned long**)(ESP + 4 + 24) /*ViewSize*/           0x00daae28 {0x00000000} unsigned long *
*(int*)(ESP + 4 + 28)            /*InheritDisposition*/ 0x00000001              int
*(unsigned long*)(ESP + 4 + 32)  /*AllocationType*/     0x00800000              unsigned long
*(unsigned long*)(ESP + 4 + 36)  /*Protect*/            0x00000002              unsigned long

程序集演练

我最初是通过在 VS 的调试器中启用 break-on-throw 来捕获异常的,然后我就能够查明第一个失败的调用并在前面放置一个断点。这是我在反汇编内部进行调试时可以看到的内容(> 标记当前指令):

  _NtMapViewOfSection@40:
  76F2EF60  mov         eax,28h  
  76F2EF65  mov         edx,offset _Wow64SystemServiceCall@0 (76F43430h)  
> 76F2EF6A  call        edx  
  76F2EF6C  ret         28h  
  76F2EF6F  nop  

...进入:

  _Wow64SystemServiceCall@0:
> 76F43430  jmp         dword ptr [_Wow64Transition (76FD2218h)]  

...进入:

> 74A37000  jmp         0033:74A37009  
  74A37007  add         byte ptr [eax],al  
  74A37009  inc         ecx  
  74A3700A  jmp         dword ptr [edi+0F8h]  

...进入:

  _NtQueryObject@20:
  76F2EDC0  mov         eax,10h  
  76F2EDC5  mov         edx,offset _Wow64SystemServiceCall@0 (76F43430h)  
  76F2EDCA  call        edx  
> 76F2EDCC  ret         14h  
  76F2EDCF  nop  

下一个进入会触发异常。


对程序环境的干扰,例如:

  • 更新编译器和运行时(在 MSVC90 和 MSVC141 之间),这首先揭示了错误;
  • 在发布和调试配置之间切换;
  • 通过 /base 链接器标志强制 OCX 的基地址;
  • 在附加调试器的情况下运行;
  • 使用 drstrace.exe 监控系统调用;

... 更改对 NtMapViewOfSection 的调用将成功或失败,似乎是随机的:并非所有调用都失败,但有相当一部分会失败。事实上,错误的第一次出现可能并不能说明问题的实际来源,因为我很少能够使它更早地崩溃(在卸载控件时),甚至在 none 的情况下发生崩溃 我们的代码在调用堆栈上(通过直接退出 TstCon.exe)。

我找不到任何文档(官方或其他)提及 STATUS_BUFFER_TOO_SMALL 或在此上下文中的 0xC0000023 代码。我一直无法在失败的调用中找到模式,并且在 Dr. Memory 运行中没有看到相关的访问错误。

那么......这个过程中可能发生了什么导致出现这种症状?

最佳答案

在长时间检查 ActiveX 控件的执行后,使用调试器跳过特定的代码部分,我将错误的可能位置缩小到单个函数。事实证明,问题的根源几乎无法猜测。

有一天,有人希望能够为线程命名。为此,他们使用了记录在案的 0x406D1388技术(事实上,代码几乎是从链接文档中复制粘贴的)。这本身就很好。但是后来他们想要(或者我收集到)以编程方式检索名称,自定义异常方法不支持。这一切都是在 SetThreadDescription/GetThreadDescription 存在之前发生的,所以他们寻找另一种方法。 男人他们有创造力。

除了对抛出自定义异常的函数的调用之外,还有以下几行:

// Grab the TIB.
P_T_TIB pTib = GetTIB();

if (pTib == NULL)
    return false;

// If someone has already written to the arbitrary field, I don't
// want to be overwriting it.
if (pTib->pvArbitrary == NULL)
{
    // Nothing's there. Set the name.
    pTib->pvArbitrary = (void *)pszName;
}

有什么,当然绝对不是“无”。 GetTIB定义如下:

// A static function to get the TIB.
static P_T_TIB GetTIB()
{
    P_T_TIB pTib = NULL;

    _asm
    {
        MOV  EAX, FS:[18h]
        MOV  pTib, EAX
    }

    return pTib;
}

据我所知,这段高度可疑的程序集检索了一个指向 Thread Information Block 的指针。当前线程的。 T_TIB 的定义遵循该页面上的描述,并允许线程命名函数将指向名称的指针存储到任意数据槽中。在名称获取函数中使用了相同的技术来检索指针并返回名称。

当然,难点在于“任意”并不代表“用户数据”,NtMapViewOfSection和小伙伴们都是依赖字段来存储信息的,字段上放置的数据断点就是明证被 LdrpMapViewOfSection 等击中。在他们路径的某个地方,遇到具有异常非零值(即我们的名称指针)的字段导致他们执行一些非常错误的操作,最终触发了那个奇怪的异常。

出于好奇,我完全删除了所有这些,因为它没有在其他任何地方使用,并且只是使用了一个 thread_local 变量来存储名称。结案了!

关于c++ - `LoadLibraryExW` 从 `0xC0000023` 触发异常 `NtMapViewOfSection`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53767707/

有关c++ - `LoadLibraryExW` 从 `0xC0000023` 触发异常 `NtMapViewOfSection`的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby - 触发器 ruby​​ 中 3 点范围运算符和 2 点范围运算符的区别 - 2

    请帮助我理解范围运算符...和..之间的区别,作为Ruby中使用的“触发器”。这是PragmaticProgrammersguidetoRuby中的一个示例:a=(11..20).collect{|i|(i%4==0)..(i%3==0)?i:nil}返回:[nil,12,nil,nil,nil,16,17,18,nil,20]还有:a=(11..20).collect{|i|(i%4==0)...(i%3==0)?i:nil}返回:[nil,12,13,14,15,16,17,18,nil,20] 最佳答案 触发器(又名f/f)是

  3. ruby-on-rails - Rails - 乐观锁定总是触发 StaleObjectError 异常 - 2

    我正在学习Rails,并阅读了关于乐观锁的内容。我已将类型为integer的lock_version列添加到我的articles表中。但现在每当我第一次尝试更新记录时,我都会收到StaleObjectError异常。这是我的迁移:classAddLockVersionToArticle当我尝试通过Rails控制台更新文章时:article=Article.first=>#我这样做:article.title="newtitle"article.save我明白了:(0.3ms)begintransaction(0.3ms)UPDATE"articles"SET"title"='dwdwd

  4. ruby - #之间? Cooper 的 *Beginning Ruby* 中的错误或异常 - 2

    在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee

  5. ruby-on-rails - 如何在 Rails Controller Action 上触发 Facebook 像素 - 2

    我有一个ruby​​onrails应用程序。我按照facebook的说明添加了一个像素。但是,要跟踪转化,Facebook要求您将页面置于达到预期结果时出现的转化中。即,如果我想显示客户已注册,我会将您注册后转到的页面作为成功对象进行跟踪。我的问题是,当客户注册时,在我的应用程序中没有登陆页面。该应用程序将用户带回主页。它在主页上显示了一条消息,所以我想看看是否有一种方法可以跟踪来自Controller操作而不是实际页面的转化。我需要计数的Action没有页面,它们是ControllerAction。是否有任何人都知道的关于如何执行此操作的gem、文档或最佳实践?这是进入布局文件的像素

  6. ruby - 在 Ruby 中重新分配常量时抛出异常? - 2

    我早就知道Ruby中的“常量”(即大写的变量名)不是真正常量。与其他编程语言一样,对对象的引用是唯一存储在变量/常量中的东西。(侧边栏:Ruby确实具有“卡住”引用对象不被修改的功能,据我所知,许多其他语言都没有提供这种功能。)所以这是我的问题:当您将一个值重新分配给常量时,您会收到如下警告:>>FOO='bar'=>"bar">>FOO='baz'(irb):2:warning:alreadyinitializedconstantFOO=>"baz"有没有办法强制Ruby抛出异常而不是打印警告?很难弄清楚为什么有时会发生重新分配。 最佳答案

  7. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  8. SPI接收数据异常问题总结 - 2

    SPI接收数据左移一位问题目录SPI接收数据左移一位问题一、问题描述二、问题分析三、探究原理四、经验总结最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。一、问题描述根据从机芯片手

  9. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  10. ruby - Faye WebSocket,关闭处理程序被触发后重新连接到套接字 - 2

    我有一个super简单的脚本,它几乎包含了FayeWebSocketGitHub页面上用于处理关闭连接的内容:ws=Faye::WebSocket::Client.new(url,nil,:headers=>headers)ws.on:opendo|event|p[:open]#sendpingcommand#sendtestcommand#ws.send({command:'test'}.to_json)endws.on:messagedo|event|#hereistheentrypointfordatacomingfromtheserver.pJSON.parse(event.d

随机推荐