由于易博龙接手Delphi后,对编译器做了些修改,导致Delphi7以后的版本跨单元变量引用发生了改变,现举例说明如下:

代码:
unit Unit1;

interface

uses 
  nt_status, ntoskrnl, unit2;

function _DriverEntry(pDriverObject: PDriverObject; RegistryPath: PUnicodeString) : NTSTATUS; stdcall;

implementation

procedure DriverUnload(pDriverObject: PDriverObject); stdcall;
begin

end;

function _DriverEntry(pDriverObject: PDriverObject; RegistryPath: PUnicodeString) : NTSTATUS; stdcall;
begin
  asm
    int  3;
  end;
  pDriverObject^.DriverUnload := @DriverUnload;
  test1 := 100;
  ChangeOffset;
  test3 := $3A3A;               

  DbgPrint('offset %d, test1=%d, test2=%d, test3=%d'#13#10, ShareNameOffset, test1, test2, test3);
  recTest.b := $7F7F;
  DbgPrint('myRec.a = %d, myRec.b = %d'#13#10, recTest.a, recTest.b); 
  Result:= STATUS_SUCCESS;
end;

end.
代码:
unit Unit2;

interface

uses 
  nt_status, ntoskrnl;
  
type
  myRec = packed record
    a: integer;
    b: integer;
  end;

var
  ShareNameOffset: ULONG = 0;    //全局变量
  test1: DWORD;
  test2: DWORD = 1000;
  test3: DWORD;
  recTest: myRec = (a:10; b:100);

procedure ChangeOffset;

implementation

procedure ChangeOffset;
begin
  ShareNameOffset:= $ABC;     //修改
 test2 := $2000;
  recTest.a := $1A1A;
  recTest.b := $2A2A;
end;

end.
以上程序在单元unit2中定义了公共变量ShareNameOffset、test1、test2、test3及recTest记录,其中ShareNameOffset和recTest在定义时就进行了初始化(编译后这几个变量会被放入DATA段),test1、test2和test3没有进行初始化(编译后这几个变量会被放入BSS段),同时在unit2里定义过程ChangeOffset对变量进行赋值操作,在unit1单元里对在unit2里定义的一些变量进行赋值操作并用DbgPrint对unit2定义的变量值进行输出。我们先看下用Delphi7编译这个驱动生成的相关代码:
代码:
                public start
start           proc near

arg_0           = dword ptr  8

                push    ebp
                mov     ebp, esp
                int     3               ; Trap to Debugger
                mov     eax, [ebp+arg_0]
                mov     dword ptr [eax+34h], offset sub_10280
                mov     dword_103B4, 64h ; test1 := 100
                call    sub_10344
                mov     dword_103B8, 3A3Ah ; test3 := 3A3A
                mov     eax, dword_103B8
                push    eax
                mov     eax, dword_103A4
                push    eax
                mov     eax, dword_103B4
                push    eax
                mov     eax, dword_103A0
                push    eax
                push    offset Format   ; "offset %d, test1=%d, test2=%d, test3=%d"...
                call    DbgPrint
                add     esp, 14h
                mov     eax, 7F7Fh
                mov     dword_103AC, eax ; recTest.b := $7F7F
                push    eax
                mov     eax, dword_103A8
                push    eax
                push    offset aMyrec_aDMyrec_ ; "myRec.a = %d, myRec.b = %d\r\n"
                call    DbgPrint
                add     esp, 0Ch
                xor     eax, eax
                pop     ebp
                retn    8
start           endp

dword_103A0     dd 0   
                       
dword_103A4     dd 3E8h
                       
dword_103A8     dd 0Ah 
                       
dword_103AC     dd 64h 
                       
                db    0
                db    0
                db    0
                db    0
dword_103B4     dd 0   
                       
dword_103B8     dd 0
代码:
下面是用Delphi2010生成的驱动代码:
                public start
start           proc near

arg_0           = dword ptr  8

                push    ebp
                mov     ebp, esp
                int     3               ; Trap to Debugger
                mov     eax, [ebp+arg_0]
                mov     dword ptr [eax+34h], offset sub_10280
                mov     eax, off_103E0
                mov     dword ptr [eax], 64h ; test1 := 64
                call    sub_10390
                mov     eax, off_103E4
                mov     dword ptr [eax], 3A3Ah ; test3 := $3A3A
                mov     eax, off_103E4
                mov     eax, [eax]
                push    eax
                mov     eax, off_103FC
                mov     eax, [eax]
                push    eax
                mov     eax, off_103E0
                mov     eax, [eax]
                push    eax
                mov     eax, off_103F8
                mov     eax, [eax]
                push    eax
                push    offset Format   ; "offset %d, test1=%d, test2=%d, test3=%d"...
                call    DbgPrint
                add     esp, 14h
                mov     edx, off_10400
                mov     eax, 7F7Fh      ; recTest.b := $7F7F
                mov     [edx+4], eax
                mov     edx, off_10400
                push    eax
                mov     eax, off_10400
                mov     eax, [eax]
                push    eax
                push    offset aMyrec_aDMyrec_ ; "myRec.a = %d, myRec.b = %d\r\n"
                call    DbgPrint
                add     esp, 0Ch
                xor     eax, eax
                pop     ebp
                retn    8
start           endp

off_103E0       dd offset unk_10408 ;Delphi2010里这变成指针了  
                                     
off_103E4       dd offset unk_1040C  
                                     
dword_103E8     dd 0                 
                                     
dword_103EC     dd 3E8h              
                                     
dword_103F0     dd 0Ah               
                                     
dword_103F4     dd 64h               
off_103F8       dd offset dword_103E8
off_103FC       dd offset dword_103EC
off_10400       dd offset dword_103F0
                                     
                align 8
unk_10408       db    0              
                db    0
                db    0
                db    0
unk_1040C       db    0              
                db    0
                db    0
                db    0
                db    0
                db    0
                db    0
                db    0
                db    0
                db    0
                db    0
                db    0
                db    0
                db    0
                db    0
                db    0
                db    0
                db    0
                db    0
                db    0
大家对比一下两个代码就能发现区别:D7里是直接引用相关变量,而在D2010里变成了指针引用,具体的指针值是由链接器在链接程序时填充的,而我们写驱动时是用Delphi编译,用M$ Link链接,M$ Link是不会帮我们填充这个指针值的,这就导致我们的程序访问了非法的内存空间,从而出现BSOD。目前最新版的rmcoff2(2.0.0.87及后续版本)会对每个单元导出的公共变量进行修正,为我们生成这个指针,处理后就会得到我们想要的结果。但是大家在嵌入汇编里访问其它单元里定义的变量时就要根据Delphi的不同版本写不同的代码了,因为对嵌入式汇编,Delphi编译器基本是尊重原著的^_^。举个例子:
代码:
unit seh;

interface

uses
  nt_status;

//: SEH
{异常处理}
const
  SEH_SafePlaceCounter  = 0;
  SEH_INSTALLED          = 0;

type
  _SEH = record
    SafeEip: DWORD; {The offset where it's safe to continue execution}
    PrevEsp: DWORD; {The previous value of esp}
    PrevEbp: DWORD; {The previous value of ebp}
end;

var
  sseh: _SEH; ///:~  

function DefaultExceptionHandler(pExcept:PEXCEPTION_RECORD; pFrame:DWORD; p_Context:PCONTEXT; pDispatch:DWORD): DWORD; cdecl;

implementation

uses
  ntoskrnl;

//: DefaultExceptionHandler
function DefaultExceptionHandler(pExcept:PEXCEPTION_RECORD;
                                 pFrame:DWORD;
                                 p_Context:PCONTEXT;
                                 pDispatch:DWORD): DWORD; cdecl;
begin
  DbgPrint('Exception: %08X at address: %08X'#13#10,
            pExcept^.ExceptionCode,
            pExcept^.ExceptionAddress);
  asm
    lea eax, sseh
    push (_SEH PTR [eax]).SafeEip
    push (_SEH PTR [eax]).PrevEsp
    push (_SEH PTR [eax]).PrevEbp

    mov eax, pContext
    pop (CONTEXT PTR [eax]).regEbp
    pop (CONTEXT PTR [eax]).regEsp
    pop (CONTEXT PTR [eax]).regEip
  end;
  result := 0;
end; ///:~

end.
我们在seh单元里定义了一个结构_SEH,并定义了一个公共变量sseh。现在我们在别的单元里通过嵌入汇编填充该结构,如果是Delphi7,你可以写成
 
代码:
{安装SEH}
  asm
              push offset DefaultExceptionHandler
              push fs:[0]
              mov fs:[0], esp

              mov sseh.SafeEip, offset SafePlace
              mov sseh.PrevEbp, ebp
              mov sseh.PrevEsp, esp
  end;
但如果是D7以后的版本,你就要写成:
代码:
{安装SEH}
          asm
            push offset DefaultExceptionHandler
            push fs:[0]
            mov fs:[0], esp

            mov eax, dword ptr sseh ;在D2010里,sseh是个指针
            mov (_SEH PTR [eax]).SafeEip, offset SafePlace
            mov (_SEH PTR [eax]).PrevEbp, ebp
            mov (_SEH PTR [eax]).PrevEsp, esp
          end;
对于嵌入汇编的这个差别大家就一定要注意了,这个rmcoff也无能为力,只有大家写程序的时候自己注意了。不过我还是推荐大家用Delphi2010写驱动,因为2010提供的一些新特性可以大大降低写驱动的复杂性。当然Kmdkit4D会尽力兼容Delphi7的。