在反汇编一个windows下的usb设备驱动的过程中,我发现windows环境下的内存地址偏移计算结果与IDA计算结果的差异。最主要体现在偏移量的计算上,windows环境下的偏移是按照源地址类型来确定偏移量的。
源代码:
.text:00010C78 ; ---------------------------------------------------------------------------
.text:00010C7B align 4
.text:00010C7C
.text:00010C7C ; =============== S U B R O U T I N E =======================================
.text:00010C7C
.text:00010C7C ; Attributes: bp-based frame
.text:00010C7C
.text:00010C7C sub_10C7C proc near ; CODE XREF: sub_10F08+100p
.text:00010C7C
.text:00010C7C DestinationString= UNICODE_STRING ptr -8
.text:00010C7C arg_0 = dword ptr 8
.text:00010C7C
.text:00010C7C push ebp
.text:00010C7D mov ebp, esp
.text:00010C7F push ecx
.text:00010C80 push ecx
.text:00010C81 push ebx
.text:00010C82 push esi
.text:00010C83 push edi ;保存现场
.text:00010C84 mov edi, [ebp+arg_0] ;edi获取第一个参数
.text:00010C87 mov esi, [edi+28h] ;esi = *(edi+40)
.text:00010C8A lea eax, [esi+74h] ;eax = *(esi+116)
.text:00010C8D push eax ; SourceString 保存源字符串的指针,调用规则,从左至右
.text:00010C8E lea eax, [ebp+DestinationString]
.text:00010C91 push eax ; DestinationString 保存目的字符串指针
.text:00010C92 call ds:RtlInitUnicodeString ;调用RtlInitUnicodeString 函数
.text:00010C98 push 0 ; Enable ;参数0
.text:00010C9A lea eax, [ebp+DestinationString] ;获取目的字符串
.text:00010C9D push eax ; SymbolicLinkName ;保存至堆栈
.text:00010C9E call ds:IoSetDeviceInterfaceState ;调用IoSetDeviceInterfaceState
.text:00010CA4 mov ebx, ds:ExFreePool ;保存函数指针,以便下面call调用
.text:00010CAA mov [ebp+arg_0], eax ;
.text:00010CAD mov eax, [esi+10h]
.text:00010CB0 test eax, eax ;eax==0?
.text:00010CB2 jz short loc_10CB7
.text:00010CB4 push eax ;
.text:00010CB5 call ebx ; ExFreePool
.text:00010CB7
.text:00010CB7 loc_10CB7: ; CODE XREF: sub_10C7C+36j
.text:00010CB7 mov esi, [esi+14h]
.text:00010CBA test esi, esi
.text:00010CBC jz short loc_10CC1
.text:00010CBE push esi ; P
.text:00010CBF call ebx ; ExFreePool
.text:00010CC1
.text:00010CC1 loc_10CC1: ; CODE XREF: sub_10C7C+40j
.text:00010CC1 push edi
.text:00010CC2 call sub_1088A
.text:00010CC7 mov eax, [ebp+arg_0]
.text:00010CCA pop edi
.text:00010CCB pop esi
.text:00010CCC pop ebx
.text:00010CCD leave
.text:00010CCE retn 4
.text:00010CCE sub_10C7C endp
如果以汇编的模式,这种偏移是对的,但是逆向回C语言格式的时候可就要注意了,因为Win32的地址偏移和源地址的类型有关。
例如地址00010C87 处的代码:mov esi, [edi+28h] ;意思就是esi = *(edi+40),根据上下文分析,传进来的参数是PDEVICE_OBJECT,那么你要是直接写成C语句:(ULONG*)(arg_0+40),这样就会导致错误,为啥?原因是地址偏移了sizeof(DEVICE_OBJECT)*40,就成了mov esi, [edi+1cc0h]了。
汇编语句下的偏移都是以char的长度计数的,因此,若把C语句改成(ULONG*)arg_0 + 10,或者(char*)arg_0+40,这样的语句在C语言下偏移正确了,+10的原因不用说了吧(ULONG = char*4)。
总结经验:
mov eax, [edi+60h]
sub eax, 24h
此语句就是(char*)Irp->Tail.Overlay.CurrentStackLocation-24h,即为Irp->Tail.Overlay.CurrentStackLocation-1,进而表明此处使用了宏IoGetNextIrpStackLocation.