代码:
{***************
功能 获取kernel32.dll 的模块基地址
返回 k32基址
作者 饿狼传说 (lofullen)
***************}
FUNCTION GetKernel32Module(): Cardinal; assembler
asm
  push esi
  mov eax, fs:$30
  mov eax, [eax+$0c]
  mov esi, [eax+$1c]
  lodsd
  mov eax, [eax+$08] 
  pop esi
end;

{***************
功能 计算字符串的长度
参数 eax = 字符串首指针
返回 长度
作者 饿狼传说 (lofullen)
***************}
FUNCTION LStrLengthA(const lpStr: PAnsiChar): Cardinal; assembler;
asm
     push    edi
     push    ebx
     mov     edi, eax
     mov     ebx, eax
     xor     al, al                   // al = 00 遇到字符串末尾则退出循环
     mov     cx, 255                  // cx = ff 字符串超过255则退出循环
     repne   scasb
     dec     edi
     sub     edi, ebx
     mov     eax, edi
     pop     ebx
     pop     edi
end;

{***************
功能 计算短字符串精确CRC32
参数 eax = 字符串首指针
返回 crc32
作者 饿狼传说 (lofullen)
***************}
FUNCTION CalcBufferCRC(lpBuffer:PAnsiChar): Cardinal; assembler;
var
  checksum : DWORD;
asm
  push ebx
  push ecx
  push edx
  push edi
  push esi
  mov ebx, eax
  call LStrLengthA                    // eax = 字符串长度
  xor edx, edx                        // edx = 整除后的余数
  mov ecx, 4
  div ecx
  xor ecx, ecx
@@loopBegin:
  dec eax                             // eax = 整除后的整数
  jl @@loopOver
  xor ecx, dword ptr ds:[ebx]         // ecx = CRC32
  add ebx, 4
  jmp @@loopBegin
@@loopOver:
  test edx, edx                       // 如果有余数则执行
  je @@Nochecksum
  mov eax, ecx
  mov esi, ebx                        // esi = 剩余字节的首指针
  lea edi, checksum
  mov dword ptr ds:[edi], 0           // checksum 归零 这样的做法为了保证只读取 00 之前的剩余字节
  mov ecx, edx
  rep movsb                           // checksum 得到剩余字节(自然是小于4咯) 
  lea edi, checksum
  xor eax, dword ptr ds:[edi]         // 最后一次计算
  jmp @@calcEnd
@@Nochecksum:
  mov eax, ecx                        // 直接获取 ECX 中的 CRC32
@@calcEnd:
  pop esi
  pop edi
  pop edx
  pop ecx
  pop ebx
end;

{***************
功能 计算API输出函数地址
参数 eax = 模块基地址
参数 edx = 函数 CRC32
返回 函数指针
作者 饿狼传说 (lofullen)
***************}
function GetProcAddressA(hModule:Cardinal; dwExportCRC: Cardinal) : Pointer; assembler;
var
  lpProcNameCRC, dwProcNumber: Cardinal;
  pProcAddress, pProcNameAddress, pProcIndexAddress: Pointer;
asm
  push ebx
  push esi
  mov lpProcNameCRC, edx      // edx=函数名CRC32
  mov ebx, eax                // ebx=基址
  mov eax, [ebx+$3c]          // eax=文件头偏移
  mov esi, [ebx+eax+$78]      // esi=输出表偏移,文件头+可选头的长度=$78
  lea esi, [ebx+esi+$18]      // esi=函数名数量 = 函数数量 [ebx+esi+$14]
  lodsd
  mov dwProcNumber, eax       // eax=函数名数量
  lodsd
  mov pProcAddress, eax       // eax=函数偏移量
  lodsd
  mov pProcNameAddress, eax   // eax=函数名偏移量
  lodsd
  mov pProcIndexAddress, eax  // eax=序列号偏移量
  mov edx, dwProcNumber       // edx=遍历次数
@@LoopBegin:
  xor eax, eax                // Result = 0
  dec edx
  jl @@LoopEnd
  mov eax, pProcNameAddress
  add eax, ebx                // eax=函数名基地址
  mov eax, dword ptr ds:[eax+edx*4]
  add eax, ebx                // eax=遍历函数名
  call CalcBufferCRC
  cmp eax, lpProcNameCRC      // 对比HASH
  jnz @@LoopBegin
  shl edx, 1
  add edx, pProcIndexAddress  // 函数基序列
  movzx eax, word ptr ss:[edx+ebx]
  shl eax, 2
  add eax, pProcAddress       // 函数基地址
  mov eax, [eax+ebx]
  add eax, ebx                // Result = 函数地址
@@LoopEnd:
  pop esi
  pop ebx
end;

// 功能 数值转字符
// 配合 IntToStrA IntToHexA  不可单独使用
// delphi system.pas 

procedure CvtInt;
asm
        OR      CL,CL
        JNZ     @CvtLoop
@C1:    OR      EAX,EAX
        JNS     @C2
        NEG     EAX
        CALL    @C2
        MOV     AL,'-'
        INC     ECX
        DEC     ESI
        MOV     [ESI],AL
        RET
@C2:    MOV     ECX,10

@CvtLoop:
        PUSH    EDX
        PUSH    ESI
@D1:    XOR     EDX,EDX
        DIV     ECX
        DEC     ESI
        ADD     DL,'0'
        CMP     DL,'0'+10
        JB      @D2
        ADD     DL,('A'-'0')-10
@D2:    MOV     [ESI],DL
        OR      EAX,EAX
        JNE     @D1
        POP     ECX
        POP     EDX
        SUB     ECX,ESI
        SUB     EDX,ECX
        JBE     @D5
        ADD     ECX,EDX
        MOV     AL,'0'
        SUB     ESI,EDX
        JMP     @z
@zloop: MOV     [ESI+EDX],AL
@z:     DEC     EDX
        JNZ     @zloop
        MOV     [ESI],AL
@D5:
end;

// 功能 数字型转成 10进制 字符串型(pchar版)
// 参数 EAX = 10进制数字
// 参数 EDX = 指向字符串(array[0..100] of char)指针
// 返回 有效字符串长度 
//作者 饿狼传说 (lofullen)

function IntToStrA(Value: Integer; lpBuffer: Pchar): Cardinal; assembler;
asm
        PUSH    ESI
        MOV     ESI, ESP
        SUB     ESP, 16
        PUSH    EDI
        MOV     EDI, ECX
        XOR     ECX, ECX       // base: 0 for signed decimal
        PUSH    EDX            // result ptr
        XOR     EDX, EDX       // zero filled field width: 0 for no leading zeros
        CALL    CvtInt
        MOV     EAX, ECX
        REP     MOVSB
        POP     EDI
        ADD     ESP, 16
        POP     ESI
end;

// 功能 数字型转成 16进制 字符串型(pchar版)
// 参数 EAX = 10进制数字
// 参数 EDX = 16进制字符串格式长度
// 参数 ECX = 指向字符串(array[0..100] of char)指针
// 返回 有效字符串长度 
//作者 饿狼传说 (lofullen)

function IntToHexA(Value: Integer; Digits: Integer; lpBuffer: Pchar): Cardinal; assembler;
asm
        CMP     EDX, 32        // Digits < buffer length?
        JBE     @A1
        XOR     EDX, EDX
@A1:    PUSH    ESI
        MOV     ESI, ESP
        SUB     ESP, 32
        PUSH    EDI
        MOV     EDI, ECX
        MOV     ECX, 16        // base 16     EDX = Digits = field width
        CALL    CvtInt
        MOV     EAX, ECX
        REP     MOVSB
        POP     EDI
        ADD     ESP, 32
        POP     ESI
end;


{***************
功能 移位 * 10 
配合 HexToIntA 不能单独使用
作者 饿狼传说 (lofullen)
***************}

procedure MoveBit;
asm
  push ebp
  mov ebp, esi
  sub ebp, edx
@@loop:
  dec ebp
  jl @@end
  shl ecx, 4
  jmp @@loop
@@end:
  pop ebp
end;

{***************
功能 16进制字符转换成10进制数值
参数 eax = 16进制字符串
返回 10进制整型
作者 饿狼传说 (lofullen)
***************}

function HexToIntA(lpToken : Pchar): Cardinal;
asm
  push ebx
  push ecx
  push edx
  push edi
  push esi
  mov ebx, eax            //ebx = hex
  call LStrLengthA
  mov edx, eax            //edx = hex bit
  mov esi, eax
  sub esi, 1              //esi = low bit
  xor edi, edi
@@Machine:
  dec edx
  jl @@IntoOver
  mov al, byte ptr ds:[ebx+edx]
@@step1:                 //0~9
  cmp al, '0'
  jl @@IntoOver
  cmp al, '9'
  jg @@step2
  sub al, 48
  movzx ecx, al
  call MoveBit
  add edi, ecx
  jmp @@Machine
@@step2:                 //A-F
  cmp al, 'A'
  jl @@IntoOver
  cmp al, 'F'
  jg @@step3
  sub al, 65
  add al, 10
  movzx ecx, al
  call MoveBit
  add edi, ecx
  jmp @@Machine
@@step3:                 //a-f
  cmp al, 'a'
  jl @@IntoOver
  cmp al, 'f'
  jg @@IntoOver
  sub al, 97
  add al, 10
  movzx ecx, al
  call MoveBit
  add edi, ecx
  jmp @@Machine
@@IntoOver:
  mov eax, edi
  pop esi
  pop edi
  pop edx
  pop ecx
  pop ebx
end;

var
  RandSeed : int64; // 随机数因子

//功能 通过查询 CPU 或者 运行时钟获取随机数因子
//作者 饿狼传说 (lofullen)

procedure Randomize;
var
  Counter: Int64;
asm
  push edx
  lea eax, Counter
  push eax
  call QueryPerformanceCounter
  mov eax, DWORD PTR SS:[Counter]
  test eax, eax
  je @@TickCount
  mov RandSeed, eax
  jmp @@Exit
@@TickCount:
  call GetTickCount
  mov RandSeed, eax
@@Exit:
  pop edx
end;

// 功能 根据随机数因子进行返回内的运算
// 参数 EAX = 最大值 (0~n)
// 返回 随机数
// 作者 饿狼传说 (lofullen)

function Random(const ARange: Integer): Integer;
asm
        PUSH    EBX
        MOV     EBX, RandSeed                                // 某些主动防御对以下3条命令进行特征检查
        IMUL    EDX, EBX, $08088405                      // 如果配合在网络端口上进行随机, 会被报木马
        INC     EDX
        MOV     RandSeed, EDX
        MUL     EDX
        MOV     EAX, EDX
        POP     EBX
end;

// 功能 通过随机的上下限来获得一个受控随机数
// 参数 eax = 随机下限
// 参数 edx = 随机上限
// 返回 eax >= n <= edx
// 作者 饿狼传说 (lofullen)

function GetRandomSeries(const fRadix, fFactor : Integer): Int64;
asm
  push ebx
  mov ebx, eax
  sub edx, eax
  call Randomize
  mov eax, edx
  call Random
  add eax, ebx
  pop ebx
end;
以上汇编函数 全部用于KOL纯pascal 环境
本贴将不断更新函数, 并修复原有函数的BUG, 学习DELPHI内联汇编的朋友也可以更贴.

  • 标 题:答复
  • 作 者:lofullen
  • 时 间:2010-11-02 17:45:06

汇编函数自然是手工写的,但是调试的话也只能靠OD调试正确性了,
至于 API 的实现 比如你说的 ExitProcess 这API 虽然位于 kernel32.dll 但是他依然调用了 ntdll.dll , 说明是在调用底层驱动, 比如 ZwTerminateProcess ,所以你如果要实现,你得从 R0 下手了。

NTSTATUS
NtTerminateProcess(
    __in_opt HANDLE ProcessHandle,
    __in NTSTATUS ExitStatus
    )

/*++

Routine Description:

    This function causes the specified process and all of
    its threads to terminate.

Arguments:

    ProcessHandle - Supplies a handle to the process to terminate.

    ExitStatus - Supplies the exit status associated with the process.

Return Value:

    NTSTATUS - Status of operation

--*/

{

    PETHREAD Thread, Self;
    PEPROCESS Process;
    PEPROCESS CurrentProcess;
    NTSTATUS st;
    BOOLEAN ProcessHandleSpecified;
    PAGED_CODE();

    Self = PsGetCurrentThread();
    CurrentProcess = PsGetCurrentProcessByThread (Self);

    if (ARGUMENT_PRESENT (ProcessHandle)) {
        ProcessHandleSpecified = TRUE;
    } else {
        ProcessHandleSpecified = FALSE;
        ProcessHandle = NtCurrentProcess();
    }

    st = ObReferenceObjectByHandle (ProcessHandle,
                                    PROCESS_TERMINATE,
                                    PsProcessType,
                                    KeGetPreviousModeByThread(&Self->Tcb),
                                    &Process,
                                    NULL);

    if (!NT_SUCCESS (st)) {
        return(st);
    }

    if (Process->Flags & PS_PROCESS_FLAGS_BREAK_ON_TERMINATION) {
        PspCatchCriticalBreak ("Terminating critical process 0x%p (%s)\n",
                               Process,
                               Process->ImageFileName);
    }

    //
    // Acquire rundown protection just so we can give the right errors
    //

    if (!ExAcquireRundownProtection (&Process->RundownProtect)) {
        ObDereferenceObject (Process);
        return STATUS_PROCESS_IS_TERMINATING;
    }

    //
    // Mark process as deleting except for the obscure delete self case.
    //
    if (ProcessHandleSpecified) {
        PS_SET_BITS (&Process->Flags, PS_PROCESS_FLAGS_PROCESS_DELETE);
    }

    st = STATUS_NOTHING_TO_TERMINATE;

    for (Thread = PsGetNextProcessThread (Process, NULL);
         Thread != NULL;
         Thread = PsGetNextProcessThread (Process, Thread)) {

        st = STATUS_SUCCESS;
        if (Thread != Self) {
            PspTerminateThreadByPointer (Thread, ExitStatus, FALSE);
        }
    }

    ExReleaseRundownProtection (&Process->RundownProtect);


    if (Process == CurrentProcess) {
        if (ProcessHandleSpecified) {

            ObDereferenceObject (Process);

            //
            // Never Returns
            //

            PspTerminateThreadByPointer (Self, ExitStatus, TRUE);
        }
    } else if (ExitStatus == DBG_TERMINATE_PROCESS) {
        DbgkClearProcessDebugObject (Process, NULL);
    }

    //
    // If there are no threads in this process then clear out its handle table.
    // Do the same for processes being debugged. This is so a process can never lock itself into the system
    // by debugging itself or have a handle open to itself.
    //
    if (st == STATUS_NOTHING_TO_TERMINATE || (Process->DebugPort != NULL && ProcessHandleSpecified)) {
        ObClearProcessHandleTable (Process);
        st = STATUS_SUCCESS;
    }

    ObDereferenceObject(Process);

    return st;
}