Дизассемблер длин x86 инструкций для сплайсинга

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by slesh, 14 Nov 2010.

  1. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    Когда потребовалось написать модуль для сплайсинга определенных функций, и вот для него потребовался дизассемблер длин инструкций. В принципе функции которые надо было сплайсить не юзали mmx и sse а только x86 команды.

    Когда начал искать диасм длин, то находил довольно объемный, а иногда и стрёмный код, к томуже содержащий не нужный баласт в роле примочек связанных с mmx.

    При этом был найден довольно маленький диасм длин написанный на ассемблере.

    И так вот: за основу был взят VirXasm32 v1.5b (X) Malum 2006, код был портирован под Си (для MS Visual C++) в виде асм вставки и функции обертки для более удобного использования. Кстати, код поддерживает и MMX инструкции вроде как. потому что нормально определял их длинну

    Выкладываю сюда, может комунить пригодиться.
    Предоставляются 2 функции
    1) int MDAL_GetOpcodesLenByNeedLen(BYTE* opcode, int NeedLen);
    На входе:
    * адрес начала кода
    * минимальная требуемая длинна. На выходе -
    На выходе: кол-во байт больше минимально требуемого, но составляющих целое кол-во инструкций. Или 0 - ошибка.

    2) int _cdecl MDAL_GetOpcodeLen(BYTE* opcode);
    На входе: адрес кода
    На выходе: длинна первой инструкции. 0 = ошибка

    Вот непосредственно код:
    Code:
    #include <windows.h>
    
    #define _SALC   0xD6
    #define _AAM    0xD4
    #define NRM_TAB_LEN     53
    
    #define DB __asm _emit
    
    int MDAL_GetOpcodesLenByNeedLen(BYTE* opcode, int NeedLen)
    {
            int FullLen = 0;
            int len;
    
            do
            {
                    len = MDAL_GetOpcodeLen(opcode + FullLen);
                    if (!len)
                    {
                            return 0;
                    }
                    FullLen += len;
            }
            while (FullLen < NeedLen);
    
            return FullLen;
    }
    
    __declspec(naked) int _cdecl MDAL_GetOpcodeLen(BYTE* opcode)
    {
            _asm
            {
                    mov esi, [esp + 4]
                    pushad
                    push    000001510h
                    push    0100101FFh
                    push    0FFFFFF55h
                    push    0FFFFFFF8h
                    push    0F8FF7FA0h
                    push    00F0EC40Dh
                    push    007551004h
                    push    001D005FFh
                    push    0550D5D55h
                    push    0555F0F88h
                    push    0F3F3FFFFh
                    push    00A0C1154h
                    
                    mov     edx, esi
                    mov     esi, esp
    
                    push    11001b
                    push    10110000101011000000101110000000b
                    push    10111111101100011111001100111110b
                    push    00000000000100011110101001011000b
                    mov     ebx, esp
                    sub     esp, 110
                    mov     edi, esp
    
                    cld
                    push    100
                    pop     ecx
            xa_nxtIndx:
                    bt      [ebx], ecx
                    DB _SALC
                            
                    jnc     xa_is0
                    lodsb
            xa_is0:
                    stosb
                    loop    xa_nxtIndx
                    mov     esi, edx
    
                    push    2
                    pop     ebx
                    mov     edx, ebx
            xa_NxtByte:
                    lodsb
                    push    eax
                    push    eax
                    cmp     al, 66h
                    cmove   ebx, ecx
                    cmp     al, 67h
                    cmove   edx, ecx
                    cmp     al, 0EAh
                    je      xa_jmp
                    cmp     al, 09Ah
                    jne     xa_nocall
    
                    inc     esi
            xa_jmp:
                    lea     esi, [esi+ebx+3]
            xa_nocall:
                    cmp     al, 0C8h
                    je      xa_i16
                    and     al, 0F7h
                    cmp     al, 0C2h
                    jne     xa_no16
            xa_i16:
                    inc     esi
                    inc     esi
    
            xa_no16:
                    and     al, 0E7h
                    cmp     al, 26h
                    pop     eax
                    je      xa_PopNxt
                    cmp     al, 0F1h
                    je      xa_F1
                    and     al, 0FCh
                    cmp     al, 0A0h
                    jne     xa_noMOV
                    lea     esi, [esi+edx+2]
            xa_noMOV:
                    cmp     al, 0F0h
                    je      xa_PopNxt
            xa_F1:
                    cmp     al, 64h
            xa_PopNxt:
                    pop     eax
                    je      xa_NxtByte
    
                    mov     edi, esp
                    push    edx
                    push    eax
                    cmp     al, 0Fh
                    jne     xa_Nrm
                    lodsb
            xa_Nrm:
                    pushfd
                    DB _AAM
                    DB 10h
                    xchg    cl, ah
                    cwde
                    cdq
                    xor     ebp, ebp
                    popfd
                    jne     xa_NrmGroup
    
                    add     edi, NRM_TAB_LEN
                    jecxz   xa_3
            xa_1:
                    bt      [edi], ebp
                    jnc     xa_2
                    inc     edx
            xa_2:
                    inc     ebp
                    loop    xa_1
                    jc      xa_3
                    DB _SALC
                    cdq
            xa_3:
                    shl     edx, 1
                    jmp     xa_ProcOpcode
    
            xa_NrmGroup:
                    sub     cl, 4
                    jns     xa_4
                    mov     cl, 0Ch
                    and     al, 7
            xa_4:
                    jecxz   xa_4x
            xa_5:
                    adc     dl, 1
                    inc     ebp
                    bt      [edi], ebp
                    loop    xa_5
                    jc      xa_ProcOpcode
            xa_4x:
                    shr     al, 1
    
            xa_ProcOpcode:
                    xchg    cl, al
                    lea     edx, [edx*8+ecx]
                    pop     ecx
                    pop     ebp
                    bt      [edi+2], edx
                    jnc     xa_noModRM
    
                    lodsb
                    DB _AAM
                    DB 8
                    shl     ah, 4
                    jnc     xa_isModRM
                    js      xa_enModRM
            xa_isModRM:
                    pushfd
                    test    ebp, ebp
                    jnz     xa_addr32       
                    sub     al, 6
                    jnz     xa_noSIB
                    mov     al, 5
            xa_addr32:
                    cmp     al, 4
                    jne     xa_noSIB
                    lodsb
                    and     al, 7
            xa_noSIB:
                    popfd
                    jc      xa_iWD
                    js      xa_i8
                    cmp     al, 5
                    jne     xa_enModRM
            xa_iWD: 
                    add     esi, ebp
                    inc     esi
            xa_i8:
                    inc     esi
    
            xa_enModRM:
                    test    ah, 60h
                    jnz     xa_noModRM
                    xchg    eax, ecx
                    cmp     al, 0F6h
                    je      xa_ti8
                    cmp     al, 0F7h
                    jne     xa_noModRM
                    add     esi, ebx
                    inc     esi
            xa_ti8:
                    inc     esi
    
            xa_noModRM:
                    shl     edx, 1
                    bt      [edi+2+17], edx
                    jnc     xa_Exit
                    inc     edx
                    bt      [edi+2+17], edx
                    jnc     xa_im8
                    adc     esi, ebx
            xa_im8:
                    inc     esi
    
            xa_Exit:
                    add     esp, 110+64
                    sub     esi, [esp+4]
                    mov     [esp+7*4], esi
                    popad
                    ret
            }
    }
    
    
    Размер непосредственно функции подсчета длинны текущей команды - 352 байта.
    Так что очень удобно юзать во всяком малваре, без особого увеличения размера

    Для особых извращенцев в аттаче лежит готовая DLL (1024 байта размер).
    Экспортирующая функцию
    int __stdcall GetOpcodeLen(unsigned char * opcode, int NeedLen);
    где
    1) opcode - адрес начала кода
    2) NeedLen - минимальное кол-во байт которое должно быть. Если поставить 0, то функция вернет длину первой команды.
    3) функция возвращает или длину инструкции/й или 0 в случае ошибки

    В делфи можно юзать так:

    function GetOpcodeLen(Opcode : pointer; NeedLen : integer):integer; stdcall; external 'opclen.dll' name 'GetOpcodeLen';
     

    Attached Files:

    #1 slesh, 14 Nov 2010
    Last edited: 14 Nov 2010
    1 person likes this.
    1. greki_hoy

      greki_hoy Member

      Joined:
      4 Mar 2010
      Messages:
      326
      Likes Received:
      57
      Reputations:
      41
      slesh
      создай oplen.obj чтоб от языка не зависел )
       
      #2 greki_hoy, 14 Nov 2010
      Last edited: 14 Nov 2010
      1. greki_hoy

        greki_hoy Member

        Joined:
        4 Mar 2010
        Messages:
        326
        Likes Received:
        57
        Reputations:
        41
        2slesh
        с /O1 esi сбивается после вызова MDAL_GetOpcodeLen
        у меня в црт вызывались конструкторы а в них ставились хуки при ините проги а там как раз цикл пробегается по массиву указателей после вызова первого остальные отдыхали если оптимизацию включал
        Code:
        void f0()
        {
            /* вот тут без оптимизации спасает что
             компиль сохраняет сам esi */
            call MDAL_GetOpcodeLen
            /* после вызова он сбит но в дебаге восстанавливается */
        }
        
        voif f1()
        {
            /* before use esi */  
            call f0();
            /* after use bad esi 
           тут глючит код с /O1 скомпиленный */
        }
        
        я так изменил и юзаю
        void f0()
        {
            __asm
                {
                        push   esi
                        ...
                        call   MDAL_GetOpcodeLen
                        ...
                        pop    esi
                }
        }
        
         
        #3 greki_hoy, 4 Jul 2011
        Last edited: 9 Jul 2011
        1. sn0w

          sn0w Статус пользователя:

          Joined:
          26 Jul 2005
          Messages:
          1,023
          Likes Received:
          1,258
          Reputations:
          327
          zombie disasm, 2кб - 2 таблицы и сам код байт 500, от мс компилера без оптимизаций
           
          1. sn0w

            sn0w Статус пользователя:

            Joined:
            26 Jul 2005
            Messages:
            1,023
            Likes Received:
            1,258
            Reputations:
            327
            о а ща по ситуации плюсую, вообщем в базонезависимом шеллкоде нужен сплайс, я сперва подумал, один хрен почти везде в апи mov edi,edi push ebp mov ebp,esp; но для универсальности добавлю, грац!
             
            1. mirvirusov

              mirvirusov New Member

              Joined:
              11 Jun 2021
              Messages:
              29
              Likes Received:
              3
              Reputations:
              0
              С поддержкой 64 есть сейчас что на примете ?