首页
社区
课程
招聘
求助 汇编 crash
发表于: 2014-1-7 12:45 4382

求助 汇编 crash

2014-1-7 12:45
4382
004028A2  sub         eax,0 
004028A5  mov         esi,ecx 
004028A7  je          004028FB 
004028A9  sub         eax,1 
004028AC  je          004028DA 
004028AE  sub         eax,1 
004028B1  jne         00402887 
004028B3  mov         eax,dword ptr [esp+10h] 
004028B7  test        eax,eax 
004028B9  ja          004028D0 
004028BB  push        0    
004028BD  push        esi  
004028BE  push        0    
004028C0  push        ebx  
004028C1  mov         dword ptr [ecx+14h],1 
004028C8  call        dword ptr ds:[437030h] 
004028CE  jmp         00402887 
004028D0  mov         edx,dword ptr [ecx] 
004028D2  push        eax  
004028D3  mov         eax,dword ptr [edx+14h] 
004028D6  call        eax  
004028D8  jmp         00402887 
004028DA  mov         edx,dword ptr [ecx] 
004028DC  mov         eax,dword ptr [edx+10h] 
004028DF  call        eax  
004028E1  mov         ecx,dword ptr [esi+18h] 
004028E4  push        ecx  
004028E5  call        dword ptr ds:[4371C0h] 
004028EB  call        00401200 
004028F0  push        esi  
004028F1  call        00419DAF 
004028F6  add         esp,4 
004028F9  jmp         00402887 
004028FB  mov         edx,dword ptr [ecx+18h] 
004028FE  push        0    
00402900  push        ecx  
00402901  lea         edi,[ecx+18h] 
00402904  push        ebx  
00402905  push        edx  
00402906  call        dword ptr ds:[437020h] 
0040290C  test        eax,eax 
0040290E  jne         0040292C 
00402910  mov         eax,dword ptr [edi] 
00402912  push        eax  
00402913  call        dword ptr ds:[4371C0h] 
00402919  call        00401200 
0040291E  push        esi  
0040291F  call        00419DAF 
00402924  add         esp,4 
00402927  jmp         00402887 
0040292C  mov         edx,dword ptr [esi] 

情况是这样:
已知:
跳转:004028A7  je          004028FB  已成功
跳转:0040290E  jne         0040292C  已成功
这里:00402906  call        dword ptr ds:[437020h]  是调用API CreateIoCompletionPort
在这里: 004028A5  mov         esi,ecx   执行完之后 esi不可能为0
但是在这里:0040292C  mov         edx,dword ptr [esi]  的时候 esi 为0
偶然现象,看不出来,esi在哪里可能被改变,也没有发现可能被其它线程更改的可能
因为一共只有4个线程,其它三个线程都很简单,基本处于等待状态。

[培训]科锐逆向工程师培训第53期2025年7月8日开班!

收藏
免费 0
支持
分享
最新回复 (16)
雪    币: 28
活跃值: (42)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
2
如果这段汇编是由编译器生成的,虽然给的只是个汇编片段,仅从修改 esi 寄存器的语句就不难看出,004028A5  mov         esi,ecx
如果  ecx 为 0, 那么以后的 esi 是存在为 0 的可能性的,从 esi 使用的频率来看,它肯定是一个经常被访问的变量,所以请检查你的那句 mov esi,ecx 执行完之后不可能为0是否正确,个人意见,望采纳。
2014-1-7 13:38
0
雪    币: 94
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
0040289F  mov         eax,dword ptr [ecx+14h] 
004028A2  sub         eax,0 

这是前面一 行代码,代码是编译生成的,并不是自己写的。
ecx不可能为0,这然在这一行就已经crash了。
这里:00402906  call        dword ptr ds:[437020h]  是调用API CreateIoCompletionPort
在这里也不可能调用成功。
这段代码是一个switch 其实执行的只是很有限的几行
现在我的猜测是在线程挂起的时候,其它线程溢出导致此线程的context被覆盖。
2014-1-7 13:47
0
雪    币: 28
活跃值: (42)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
那可以看一下是否有其它跳转语句,在不经过前两句的情况下,直接跳转到 mov esi,ecx了。线程挂起,其它线程溢出基本没这个可能,context 是保存在内核中,并且 nt 内核的 context 也不像 linux 那个,在栈顶保存的当前线程对象,所以不存在这个可能。如果汇编代码不长,可以贴出所有的代码,以便分析有更多的上下文。我曾经怀疑过是否是自己写的汇编过程没有保护好寄存器值,但又说是编译器编译的,所以一般不会出现这种现象。把代码贴全吧。
2014-1-7 14:22
0
雪    币: 94
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
0040286F  int         3    
00402870  mov         eax,dword ptr [esp+4] 
00402874  mov         ecx,dword ptr [eax+4] 
00402877  sub         esp,8 
0040287A  push        ebx  
0040287B  mov         ebx,dword ptr [ecx+4] 
0040287E  push        ebp  
0040287F  mov         ebp,dword ptr ds:[437040h] 
00402885  push        esi  
00402886  push        edi  
00402887  push        0FFFFFFFFh 
00402889  lea         edx,[esp+18h] 
0040288D  push        edx  
0040288E  lea         eax,[esp+24h] 
00402892  push        eax  
00402893  lea         ecx,[esp+1Ch] 
00402897  push        ecx  
00402898  push        ebx  
00402899  call        ebp  
0040289B  mov         ecx,dword ptr [esp+1Ch] 
0040289F  mov         eax,dword ptr [ecx+14h] 
004028A2  sub         eax,0 
004028A5  mov         esi,ecx 
004028A7  je          004028FB 
004028A9  sub         eax,1 
004028AC  je          004028DA 
004028AE  sub         eax,1 
004028B1  jne         00402887 
004028B3  mov         eax,dword ptr [esp+10h] 
004028B7  test        eax,eax 
004028B9  ja          004028D0 
004028BB  push        0    
004028BD  push        esi  
004028BE  push        0    
004028C0  push        ebx  
004028C1  mov         dword ptr [ecx+14h],1 
004028C8  call        dword ptr ds:[437030h] 
004028CE  jmp         00402887 
004028D0  mov         edx,dword ptr [ecx] 
004028D2  push        eax  
004028D3  mov         eax,dword ptr [edx+14h] 
004028D6  call        eax  
004028D8  jmp         00402887 
004028DA  mov         edx,dword ptr [ecx] 
004028DC  mov         eax,dword ptr [edx+10h] 
004028DF  call        eax  
004028E1  mov         ecx,dword ptr [esi+18h] 
004028E4  push        ecx  
004028E5  call        dword ptr ds:[4371C0h] 
004028EB  call        00401200 
004028F0  push        esi  
004028F1  call        00419DAF 
004028F6  add         esp,4 
004028F9  jmp         00402887 
004028FB  mov         edx,dword ptr [ecx+18h] 
004028FE  push        0    
00402900  push        ecx  
00402901  lea         edi,[ecx+18h] 
00402904  push        ebx  
00402905  push        edx  
00402906  call        dword ptr ds:[437020h] 
0040290C  test        eax,eax 
0040290E  jne         0040292C 
00402910  mov         eax,dword ptr [edi] 
00402912  push        eax  
00402913  call        dword ptr ds:[4371C0h] 
00402919  call        00401200 
0040291E  push        esi  
0040291F  call        00419DAF 
00402924  add         esp,4 
00402927  jmp         00402887 
0040292C  mov         edx,dword ptr [esi] 
0040292E  mov         eax,dword ptr [edx+0Ch] 
00402931  mov         ecx,esi 
00402933  call        eax  
00402935  jmp         00402887 
0040293A  int         3    

看看
2014-1-7 14:26
0
雪    币: 94
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
template<typename T>
DWORD WINAPI Processor<T>::run(LPVOID param)
{
	Processor<T>& procor = *(Processor<T> *)param;
	Scheduler<T>& scheder = *procor.scheder;
	HANDLE iocp = scheder.iocp;

	DWORD ready;
	ULONG_PTR key;
	WSAOVERLAPPED * overlap;
	while (true)
	{
		::GetQueuedCompletionStatus(iocp, &ready, &key, (LPOVERLAPPED *)&overlap, INFINITE);

		T * clt = (T *)key;
		switch(clt->event)
		{
		case T::EV_RECV:
			{
				if (0 >= ready)
				{
					clt->event = T::EV_DISCONNECT;
					::PostQueuedCompletionStatus(iocp, 0, (ULONG_PTR)clt, NULL);
				}
				else
				{
					clt->OnRecv(ready);
				}
			}
			break;
		case T::EV_CONNECT:
			{
				if (NULL == ::CreateIoCompletionPort((HANDLE)clt->fd, iocp, (ULONG_PTR)clt, 0))
				{
					::closesocket(clt->fd);
					delete clt;
				}
				else
				{
					clt->OnConnect();
				}
			}
			break;
		case T::EV_DISCONNECT:
			{
				clt->OnDisconnect();
				::closesocket(clt->fd);
				delete clt;
			}
			break;
		case T::EV_SEND:
			break;
		}
	}

	return 0;
}

这是C++代码,崩溃在这一行 clt->OnConnect();
0x0040292c 处未处理的异常: 0xC0000005: 读取位置 0x00000000 时发生访问冲突
2014-1-7 14:29
0
雪    币: 28
活跃值: (42)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
7
从得到的汇编看确实没有显示地修改 esi 的值,但这编译出来的代码总感觉不像是 vc  编译器的风格啊,要么就是过度优化了吧,汇编中 ecx 和 esi 都应该是相同的值 ecx = key, esi = ctl,编译器在使用这两个变量时用了两个寄存器来存取,并且在调用 CreateIoCompletionPort 时用的是 ecx ,却在下面调用 clt->OnConnect() 是神来之笔的选用了 esi 来作为该对象的地址来调用虚函数,感觉很奇怪。回到主题,esi 被改变了,是否会因为其它函数中有间接引用到 esi 的地址,如 rep 之类的指定来进行拷贝,却又没有还原呢(这属于编译器的问题了,但在拷贝时 esi 指向 0 确实不敢想像),要想解决这个问题在,ctl 前面加上 volatile ,阻止这种优化。
2014-1-7 15:07
0
雪    币: 94
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
是VC编译的,release版默认的速度优化,之所以用ecx和esi两个寄存器是因为CreateIoCompletionPort会修改ecx的值。我是调试之后才知道。
2014-1-7 15:15
0
雪    币: 94
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
我还是认为是溢出导致覆盖,因为出过几次crash,每一次位置都不一样,都是在看不出明显问题的位置出现的。
但这个才让我觉得会不会是覆盖了content,因为esi确实没有地方会改变它。
也只有溢出也会出现这种莫名其妙的崩溃吧
2014-1-7 15:19
0
雪    币: 28
活跃值: (42)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
10
vc 中使用 call ebp 把 ebp 当地址都来使用的很少见啊,那么多空闲的寄存器可用。由于函数内部会改变 ecx 的值,而让编译器在外部做保护的也是少之又少,因为在编译时,不像 MASM 那样,会标识出可能会引起哪些寄存器的变化。一般溢出才会引起这种问题,这个观点我造成,但由于内核栈溢出造成  context 的改变,这个几乎不可能。那些就还有一个情况了,用户级线程溢出导致的指令跳转异常了。
2014-1-7 15:34
0
雪    币: 28
活跃值: (42)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
11
或者是 key 的值本身不对,在访问第 0 个偏移时,造成错误。
2014-1-7 15:37
0
雪    币: 94
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
key值本身是没问题的。因为我通过esp拿到栈上保存的esi的值。
并且把该地址作为指针还原类对象成功。
类成员的值都是正常的。
2014-1-7 16:07
0
雪    币: 94
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
而且key值有错误的话,调用CreateIoCompletionPort是不可能成功的。
2014-1-7 16:09
0
雪    币: 28
活跃值: (42)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
14
那这个就奇怪了,如果每次崩溃地址不一样,强烈建议,看一下是否是其它线程跳转失误导致,但你说通过栈可以观察到是本线程的值,这就奇怪了,或者看一下头文件是否不匹配,有些函数的调用约定是否出现了不同造成了栈不平衡。
2014-1-7 16:23
0
雪    币: 94
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
我已经有点无语了,同一个程序,在win2008上正常,win2003上就崩溃。
vs2005编译的,现在用vs2013编译了一个,在win2003上测试,目前还没有崩溃,先看看情况能运行多久。
要说其它的线程,一共程序才三个线程,一个线程纯粹的sleep防止程序退出,还一个在accept,一直处于等待状态,因为没有连接。
2014-1-7 16:44
0
雪    币: 94
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
调用约定也没有什么特别的,应该全部是cdcall,如果不同应该还编译不过。
2014-1-7 16:46
0
雪    币: 28
活跃值: (42)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
17
还是加一个 volatile 限定一下吧,每次都从内存中取,免得造成寄存器被修改的问题。但是我感觉是否有其它地方修改掉了 esi 的值,而编译器没有察觉到,导致编译出来的代码不合理。
2014-1-7 16:56
0
游客
登录 | 注册 方可回帖
返回