我已经进行了更多研究,并且以下所报告的问题似乎仅在我使用Visual Studio 2017暂停该过程时发生。似乎当rip指向无效位置时,它总是从正确的指令开始起+1个字节的偏移量。
此外,就上下文而言,这是一个大型C ++项目,其中包含许多dll,一些使用MSVC 2015编译,其余使用icc(英特尔编译器2017)进行编译。这是在使用Boost C ++ / python绑定的python进程中运行的。
我正在随机暂停程序,以查看在进行大量计算时线程在做什么。 请注意,我不是在调试崩溃,请恢复程序正常运行。
但是,VS调试器有时无法反汇编机器代码。 例如,在rip = 000007FE8B048EE2的一个线程上,它显示如下:
000007FE8B048EDE ?? ??
000007FE8B048EDF ?? ??
000007FE8B048EE0 ?? ??
000007FE8B048EE1 ?? ??
}
if (params.derandomize) {
000007FE8B048EE2 adc ebp,eax
GetRNG().Seed(id);
000007FE8B048EE4 pop rax
000007FE8B048EE5 wait
000007FE8B048EE6 adc byte ptr [rax],al
000007FE8B048EE8 mov rcx,rax
解码的x86指令似乎也出错(adc,pop,wait,adc ??),所以我也尝试附加WinDBG(非侵入模式):
0:019> u rip
somedll!<lambda239>::operator()+0x132:
000007fe`8b048ee2 13e8 adc ebp,eax
000007fe`8b048ee4 58 pop rax
000007fe`8b048ee5 9b wait
000007fe`8b048ee6 1000 adc byte ptr [rax],al
000007fe`8b048ee8 4889c1 mov rcx,rax
000007fe`8b048eeb 8b9570080000 mov edx,dword ptr [rbp+870h]
000007fe`8b048ef1 e8fa911000 call somedll!bla::bla::blabla::blabla::Seed (000007fe`8b1520f0)
000007fe`8b048ef6 4c8ba5b0080000 mov r12,qword ptr [rbp+8B0h]
好吧,这是一样的垃圾... 但是后来我试图从略高于rip的地址处反汇编:
0:019> u rip-30
somedll!<lambda239>::operator()+0x102:
000007fe`8b048eb2 00488b add byte ptr [rax-75h],cl
000007fe`8b048eb5 084863 or byte ptr [rax+63h],cl
000007fe`8b048eb8 81d003000048 adc eax,48000003h
000007fe`8b048ebe 83f8ff cmp eax,0FFFFFFFFh
000007fe`8b048ec1 740a je somedll!<lambda239>::operator()+0x11d (000007fe`8b048ecd)
000007fe`8b048ec3 4889c2 mov rdx,rax
000007fe`8b048ec6 48899570080000 mov qword ptr [rbp+870h],rdx
000007fe`8b048ecd 486381e0030000 movsxd rax,dword ptr [rcx+3E0h]
0:019> u
somedll!<lambda239>::operator()+0x124:
000007fe`8b048ed4 483bd0 cmp rdx,rax
000007fe`8b048ed7 7501 jne somedll!<lambda239>::operator()+0x12a (000007fe`8b048eda)
000007fe`8b048ed9 cc int 3
000007fe`8b048eda 80b96303000000 cmp byte ptr [rcx+363h],0
000007fe`8b048ee1 7413 je somedll!<lambda239>::operator()+0x146 (000007fe`8b048ef6)
000007fe`8b048ee3 e8589b1000 call somedll!bla::bla::blabla::GetRNG (000007fe`8b152a40)
000007fe`8b048ee8 4889c1 mov rcx,rax
000007fe`8b048eeb 8b9570080000 mov edx,dword ptr [rbp+870h]
0:019> u
somedll!<lambda239>::operator()+0x141:
000007fe`8b048ef1 e8fa911000 call somedll!bla::bla::blabla::blabla::Seed (000007fe`8b1520f0)
000007fe`8b048ef6 4c8ba5b0080000 mov r12,qword ptr [rbp+8B0h]
000007fe`8b048efd 488d95f0070000 lea rdx,[rbp+7F0h]
000007fe`8b048f04 488d8dc0070000 lea rcx,[rbp+7C0h]
000007fe`8b048f0b 498b0424 mov rax,qword ptr [r12]
000007fe`8b048f0f 4c8da570080000 lea r12,[rbp+870h]
000007fe`8b048f16 488942d0 mov qword ptr [rdx-30h],rax
000007fe`8b048f1a 4c8962d8 mov qword ptr [rdx-28h],r12
000007fe`8b048eb2处的第一条指令“ add byte ptr”和“ or byte ptr”没有意义,因为rip-30可能落在一条指令的中间,但之后似乎重新同步,因为它对应于源代码:
if (id == params.dbgbreak_id) {
__debugbreak();
}
if (params.derandomize) {
GetRNG().Seed(id);
}
000007fe`8b048ecd 486381e0030000 movsxd rax,dword ptr [rcx+3E0h]
000007fe`8b048ed4 483bd0 cmp rdx,rax // if (id == params.dbgbreak_id) {
000007fe`8b048ed7 7501 jne somedll!<lambda239>::operator()+0x12a (000007fe`8b048eda)
000007fe`8b048ed9 cc int 3 // __debugbreak(); }
000007fe`8b048eda 80b96303000000 cmp byte ptr [rcx+363h],0 // if (params.derandomize)
000007fe`8b048ee1 7413 je somedll!<lambda239>::operator()+0x146 (000007fe`8b048ef6)
000007fe`8b048ee3 e8589b1000 call somedll!bla::bla::blabla::GetRNG (000007fe`8b152a40)
000007fe`8b048ee8 4889c1 mov rcx,rax
000007fe`8b048eeb 8b9570080000 mov edx,dword ptr [rbp+870h]
000007fe`8b048ef1 e8fa911000 call somedll!bla::bla::blabla::blabla::Seed (000007fe`8b1520f0)
很显然,没有任何指令以000007fe8b048ee2开头! 在000007fe8b048ee1处有je,在000007fe8b048ee3处有电话
所以...我想,嗯,调试器中有一个错误...让我们检查一下寄存器:
0:019> r
rax=ffffffffffffffff rbx=000000000021d420 rcx=000000000021d5d0
rdx=0000000002696568 rsi=0000000000005d38 rdi=0000000056eefc40
rip=000007fe8b048ee2 rsp=0000000056eef5b0 rbp=0000000056eef5e0
r8=0000000000000006 r9=000000000021d0b8 r10=0000000006456570
r11=0000000000000006 r12=0000000056eefe50 r13=00000000069a8820
r14=000000000021d1a8 r15=0000000056eefe60
iopl=0 nv up ei pl zr na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
什么? rip = 000007fe8b048ee2 ??那怎么可能?
它解释了调试器为何显示垃圾的原因:它试图从rip开始反汇编,但是rip指向指令的中间。 但是,为什么报告的撕裂是错误的?是操作系统的罪魁祸首吗? 我想念什么吗?