1. Assembler / Говнокод #25370

    0

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    43. 43
    44. 44
    45. 45
    46. 46
    47. 47
    48. 48
    49. 49
    50. 50
    51. 51
    52. 52
    53. 53
    54. 54
    55. 55
    56. 56
    57. 57
    58. 58
    59. 59
    60. 60
    61. 61
    62. 62
    63. 63
    64. 64
    65. 65
    66. 66
    67. 67
    68. 68
    69. 69
    70. 70
    71. 71
    72. 72
    73. 73
    74. 74
    75. 75
    76. 76
    77. 77
    78. 78
    79. 79
    80. 80
    81. 81
    82. 82
    83. 83
    84. 84
    85. 85
    86. 86
    87. 87
    88. 88
    format pe console 5.0
    
    entry start
    
    include 'win32ax.inc'
    
    SLEEP=1000
    
    section '.data' data readable
    
      _hello db 'Hello "https://www.govnokod.ru/"!',13,10,0
      _conout db 'CONOUT$',0
      align 8
      _conoutnt du '\??\CONOUT$',0
    
    section '.data?' data readable writeable
    
      bytes_write dd ?
      houtput dd ?
      length dd ?
    
    section '.text' code readable executable
    
    start:
      call _novice
      invoke Sleep,SLEEP
      call _advanced
      invoke Sleep,SLEEP
      call _psycho
      invoke Sleep,SLEEP
      invoke ExitProcess,0
    
    _novice:
      invoke GetStdHandle,STD_OUTPUT_HANDLE
      mov [houtput],eax
      invoke lstrlen,_hello
      mov [length],eax
      invoke WriteConsole,[houtput],_hello,[length],bytes_write,0
      ret
    
    _advanced:
      invoke CreateFileA,_conout,GENERIC_WRITE,0,0,OPEN_EXISTING,0,0
      mov [houtput],eax
      invoke lstrlen,_hello
      mov [length],eax
      invoke WriteFile,[houtput],_hello,[length],bytes_write,0
      invoke CloseHandle,[houtput]
      ret
    
    _psycho:
      push ebx
      sub esp,40
      mov ebx,esp
      mov word[ebx+24],22
      mov word[ebx+26],24
      mov dword[ebx+28],_conoutnt
      mov dword[ebx+0],24
      mov dword[ebx+4],0
      lea eax,[ebx+24]
      mov dword[ebx+8],eax
      mov dword[ebx+12],$00000040
      mov dword[ebx+16],0
      mov dword[ebx+20],0
      lea eax,[ebx+32]
      invoke NtCreateFile,houtput,$40100080,ebx,eax,0,0,0,1,$60,0,0
      invoke lstrlen,_hello
      mov [length],eax
      lea eax,[ebx+32]
      invoke NtWriteFile,[houtput],0,0,0,eax,_hello,[length],0,0
      invoke NtClose,[houtput]
      add esp,40
      pop ebx
      ret
    
    section '.import' data import readable
    
      library\
        ntdll,'ntdll.dll',\
        kernel32,'kernel32.dll'
    
      import ntdll,\
        NtClose,'NtClose',\
        NtCreateFile,'NtCreateFile',\
        NtWriteFile,'NtWriteFile'
    
      include 'api\kernel32.inc'
    
    section '.reloc' fixups data readable discardable

    Интересно какой из методов (_novice, _advanced, _psycho) вывода в консоль является говнокодом?

    Запостил: chiacorp, 10 Февраля 2019

    Комментарии (56) RSS

    • Помоему здесь самый нормальный это _novice. Только я бы здесь не звал lstrlen каждый раз, а написал бы
      mov [length], _conout - _hello - 1


      Мне вот, кстати, непонятно, почему Томаш, написав ассемблер с таким классным препроцессором, сам не юзает макросы в исходниках fasm, и даже таблицы импорта руками собирает?
      Ответить
      • В fasmg юзает по полной)
        Ответить
      • Может быть так бутстрапнуться проще было? Самая первая версия же явно не сама собой конпелялась? А потом так и оставил.
        Ответить
        • Первые версии на tasm'е были, но синтаксис у fasm с tasm'ом не совсем совместим, значит чавой-то там ему всё равно приходилось переписывать. Да и потом много чего ещё дописано было.

          Ассемблерщики любят ручками поработать, любят сэкономить лишний байт, лишний проход и лишнюю милисекунду конпеляции. Именно поэтому я за "assembler".
          Ответить
          • Писать конпелятор на асме - немного странная идея, имхо. Проблем со скоростью конпеляции не было бы даже на каком-нибудь питоне.
            Ответить
            • Вообще проблем со скоростью конпеляции программ на ассемблере нет.

              Надо бы придумать fasm++, с классами, шаблонами, констэкспрами и прочей хуйнёй и наметушить огромную библиотеку, чтобы программы конпелировались по джва часа.
              Ответить
      • Кстати, а где задаётся соглашение для invoke? Или там тупо всегда stdcall?
        Ответить
        • Тупо всегда!
          invoke stdcall
          cinvoke ccall
          Ответить
          • А fastcall и 64-битные соглашения где первые аргументы в регистрах тоже умеет?
            Ответить
            • При компиляции под 64 invoke другой подключается. Умеет.
              Ответить
              • А как обращаются с регистрами, которые будет юзать invoke? Или он сам их бекапит если надо?

                З.Ы. Я просто никогда invoke в асмах не юзал, всегда push/mov вручную писал подглядывая в соглашение о вызовах.
                Ответить
                • Уф! Открыл "INCLUDE/MACRO/PROC64.INC" чтобы посмотреть и обосрался.
                  Ответить
                  • Определение размера параметра по опкоду инструкции (наверное не говно, но код интересный):
                    else if ~ param in <xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7,xmm8,xmm9,xmm10,xmm11,xmm12,xmm13,xmm14,xmm15>
                    	virtual
                    	 origin = $
                    	 inc param
                    	 load opcode byte from origin
                    	 if opcode = 67h | opcode = 41h
                    	  load opcode byte from origin+1
                    	 end if
                    	 if opcode and 0F8h = 48h
                    	  [email protected] = 8
                    	 else if opcode = 66h
                    	  [email protected] = 2
                    	 else if opcode = 0FFh
                    	  [email protected] = 4
                    	 else
                    	  [email protected] = 1
                    	 end if
                    	end virtual
                           end if
                    Ответить
                    • Препроцессинг сам по себе интересен!
                      Ответить
                      • Это уже не совсем препроцессинг, в virtual собирается код и анализируется, вычисляется размер, получается это постпроцессинг; и потом эти данные используются для препроцессинга следующего кода.
                        Ответить
                    • Я прошу прощения, а кому это интересно?
                      Ответить
                • А можно ссыль на эти соглашения?
                  Ответить
                  • На вики вроде неплохо расписаны.

                    З.Ы. На английской. На русской только 32-битные перевели.
                    Ответить
          • >ccall
            куда ссал?
            Ответить
    • > https
      Блин, я сначала подумал, что это парсер ГК на асме...

      > _psycho
      А напрямую через syscall, как недавно для линукса делали, тогда кто? :)
      Ответить
      • > кто?
        _shizo
        Ответить
        • Скорее _mazo.
          Ответить
        • ;Windows 10 Pro x64
          _shizo:
          push ebx edi
          xor edi,edi
          sub esp,40
          mov ebx,esp
          mov word[ebx+24],22
          mov word[ebx+26],24
          mov dword[ebx+28],_conoutnt
          mov dword[ebx+0],24
          mov dword[ebx+4],edi
          lea eax,[ebx+24]
          mov dword[ebx+8],eax
          mov dword[ebx+12],$00000040
          mov dword[ebx+16],edi
          mov dword[ebx+20],edi
          lea eax,[ebx+32]
          push edi
          push edi
          push $60
          push 1
          push edi
          push edi
          push edi
          push eax
          push ebx
          push $40100080
          push houtput
          push edi
          mov eax,$55
          mov edx,$775BEA50
          call edx
          add esp,$30;$2C
          invoke lstrlen,_hello
          mov [length],eax
          lea eax,[ebx+32]
          push edi
          push edi
          push [length]
          push _hello
          push eax
          push edi
          push edi
          push edi
          push [houtput]
          push edi
          mov eax,$1A0008
          mov edx,$775BEA50
          call edx
          add esp,$28
          push [houtput]
          push edi
          mov eax,$3000F
          mov edx,$775BEA50
          call edx
          add esp,$8
          add esp,40
          pop edi ebx
          ret
          Ответить
          • > mov edx,$775BEA50
            > call edx
            Сла́бо.
            Ответить
            • Ну sysenter прямо из своего кода он не сможет дёрнуть по понятным причинам. Так что тут или этот переходник звать, или прерывание (если в винде оно ещё живое) или забить хуй на x86 и под amd64 дёргать syscall...

              З.Ы. Или можно call + systenter? Я просто не помню, что делает переходник после возврата из сисколла. Если там просто ret - то прокатит.
              Ответить
              • Ты любишь дёргать amdевушек за syscall?
                Ответить
              • Не забываем, тут уровень _shizo, а sysenter и syscall это уже _mazo.
                Ответить
              • См. ниже, например.
                Ответить
                • Ты же там просто winapi'шки дёргаешь, не сисколлы.
                  Ответить
                  • Верно, зато работать оно должно на любой винде, вне зависимости от того, по какому адресу размещены функции из ntdll. На моей Win10 x64, к примеру, NtCreateFile сидит на 0x00007FFAFA030910.
                    Ответить
                    • Дык похуй по какому адресу висит ntdll. Вообще никакие адреса знать не надо. Декомпилируешь ntdll, смотришь номера сисколлов и регистры. Остаётся заполнить их и дёрнуть инструкцию syscall (для amd64).

                      З.Ы. Но я х.з. насчёт стабильности виндовых сисколлов. Надо исследовать разные версии венды. Так то твой способ надёжнее.
                      Ответить
                      • Сисколлы действительно нестабильны. Более того, в разных версиях виндов они вообще по-разному реализованы. В моей винде, к примеру:
                        mov r10,rcx
                        mov eax,0x55
                        test byte ptr ds:[0x7FFE0308],0x1
                        jne ntdll.7FFAFA030925
                        syscall
                        ret
                        int 0x2E
                        ret

                        Флаг на 0x7FFE0308 — какое-то поле в KUSER_SHARED_DATA, видимо, поддерживает ли процессор «syscall».

                        А вот добрые люди ведут список сисколлов: https://j00ru.vexillium.org/syscalls/nt/64/
                        Ответить
                      • > Декомпилируешь ntdll

                        Декомпилировал ntdll от «Windows 95». Оказывается, на не-NT сделали шиворот-навыворот: ntdll импортирует функции из kernel32. Это примерно как на заборе слово «МЕЛ» написать...
                        Ответить
                  • А вообще, это полотнище — кусок моей старой попытки создания универсального шеллкода-загрузчика, который бы мог грузить заданную дллку в процессах любой битности, при необходимости переключаясь в x32/x64 и обратно.
                    Ответить
              • >сли в винде оно ещё живое)
                конечно, иначе какбы работали старые программы до сисенторовй эпохи?

                ABI то сохранять надро
                Ответить
                • Кстати, на «AMD» инструкции «SYSENTER/SYSEXIT» не работают в длинном режиме. На них в длинном нужно использовать «SYSCALL/SYSRET». Как достигается совместимость? Под «AMD» пишут отдельный HAL?
                  Ответить
      • _hacker
        Ответить
    • > $40100080
      > $60
      Паскалист?)
      Ответить
    • Раздутый говношеллкод: может стартовать из любого адреса; по окончанию полностью восстанавливает состояние регистров.
      format PE64 console
      
      use64;
      jmp start
      kernel32_namew du "kernel32.dll",0
      kernel32_handle dq 0
      
      write_console_name db "WriteConsoleA",0
      write_console_address dq 0
      
      get_std_handle_name db "GetStdHandle",0
      get_std_handle_address dq 0
      
      hello_world db "Hello World!"
      hello_world_len = $ - hello_world
      
      hole dq 0
      
      start:
      push rbp
      push rax
      push rcx
      push rdx
      push r8
      push r9
      push r11
      
      mov rbp, rsp
      sub rsp, 0x30
      and rsp, 0xFFFFFFFFFFFFFFF0
      
      call find_kernel32_funcs_64
      mov rcx, -11
      mov rax, [get_std_handle_address]
      call rax
      mov qword [rsp + 0x28], 0
      mov rcx, rax
      lea rdx, [hello_world]
      mov r8, hello_world_len
      lea r9, [hole]
      mov rax, [write_console_address]
      call rax
      
      mov rsp, rbp
      pop r11
      pop r9
      pop r8
      pop rdx
      pop rcx
      pop rax
      pop rbp
      ret
      Ответить
      • find_kernel32_funcs_64:
        push rax
        push rbx
        push rcx
        push rdx
        push rsi
        push rdi
        push r11
        push r8
        push r9
        
        lea rcx, [kernel32_namew]
        call find_loaded_module_64
        mov rdx, rax
        
        mov rdx, [rdx + 0x30] ;module->base / DOS_HEADER
        mov rcx, rdx
        mov qword [kernel32_handle], rcx
        
        mov r11d, dword [rdx + 0x3C]
        add rdx, r11          ;base + dos_hdr->e_lfanew / NT_HEADER
        mov r11d, dword [rdx + 0x88]
        lea rdx, [rcx + r11]  ;base + exports table RVA
        
        mov ebx, dword [rdx + 0x20]  ;AddressOfNames RVA
        lea rsi, [rcx + rbx]
        mov ebx, dword [rdx + 0x24]  ;AddressOfNameOrdinals RVA
        lea rdi, [rcx + rbx]
        mov ebx, dword [rdx + 0x1C]  ;AddressOfFunctions RVA
        lea rbx, [rcx + rbx]
        
        mov r11, rcx ;dll base
        mov rcx, 2  ;number of functions
        
        find_kernel32_funcs_64_loop:
        mov edx, dword [rsi] ;RVA
        add rdx, r11    ;name = base + *namePtr
        
        ;WriteConsole
        write_console_check:
        cmp qword [write_console_address], 0
        jnz get_std_handle_check
        
        push rcx
        lea rcx, [write_console_name]
        call strcmp64
        pop rcx
        
        cmp rax,0
        jne get_std_handle_check
        
        ;found proc
        push rcx
        push rdx
        lea rcx, [write_console_address]
        mov rdx, rdi
        mov r8, rbx
        mov r9, r11
        call load_export_64
        pop rdx
        pop rcx
        
        dec rcx
        jmp find_kernel32_funcs_64_loop_post_check
        
        ;GetStdHandle
        get_std_handle_check:
        cmp qword [get_std_handle_address], 0
        jnz find_kernel32_funcs_64_loop_post_check
        
        push rcx
        lea rcx, [get_std_handle_name]
        call strcmp64
        pop rcx
        
        cmp rax,0
        jne find_kernel32_funcs_64_loop_post_check
        
        ;found proc
        push rcx
        push rdx
        lea rcx, [get_std_handle_address]
        mov rdx, rdi
        mov r8, rbx
        mov r9, r11
        call load_export_64
        pop rdx
        pop rcx
        
        dec rcx
        
        find_kernel32_funcs_64_loop_post_check:
        cmp rcx, 0
        je find_kernel32_funcs_64_loop_end
        add rsi, 4
        add rdi, 2
        jmp find_kernel32_funcs_64_loop
        
        find_kernel32_funcs_64_loop_end:
        
        pop r9
        pop r8
        pop r11
        pop rdi
        pop rsi
        pop rdx
        pop rcx
        pop rbx
        pop rax
        ret
        Ответить
        • find_loaded_module_64:
          push rdx
          push rbx
          push r11
          
          mov r11, rcx
          
          db 0x65,0x48,0x8B,0x14,0x25,0x60,0x00,0x00,0x00 ;mov rdx, qword [gs:0x60]
          mov rdx, [rdx + 0x18] ;mdllist
          mov rdx, [rdx + 0x18] ;mlink: LDR_MODULE
          mov rcx, rdx ;mlink
          
          find_loaded_module_64_loop:
          mov rdx, [rdx]
          cmp dword [rdx + 0x30], 0 ;module->base != 0
          je find_loaded_module_64_loop
          
          push rdx
          push rcx
          mov rcx, r11
          mov rdx, [rdx+0x60]   ;module->dllName.Buffer
          call strilcmp64w
          pop rcx
          pop rdx
          
          cmp rax,0
          je find_loaded_module_64_loop_end
          
          cmp rdx, rcx
          jne find_loaded_module_64_loop
          
          find_loaded_module_64_loop_end:
          mov rax, rdx
          
          pop r11
          pop rbx
          pop rdx
          ret
          strcmp64:
          sub rsp, 0x10
          push rbx
          
          mov rax, rcx
          mov rbx, rdx
          
          strcmp64_loop:
          cmp byte [rax], 0
          je strcmp64_exit
          cmp byte [rbx], 0
          je strcmp64_exit
          
          mov cl, [rbx]
          cmp [rax], cl
          jne strcmp64_exit
          inc rax
          inc rbx
          jmp strcmp64_loop
          
          strcmp64_exit:
          mov al, [rax]
          sub al, [rbx]
          and rax, 0xFF
          
          pop rbx
          add rsp, 0x10
          ret
          
          strilcmp64w:
          sub rsp, 0x10
          push rbx
          
          mov rax, rcx
          mov rbx, rdx
          
          strilcmp64w_loop:
          cmp word [rax], 0
          je strilcmp64w_exit
          cmp word [rbx], 0
          je strilcmp64w_exit
          
          mov cx, [rbx]
          or cx, 0x20
          cmp [rax], cx
          jne strilcmp64w_exit
          add rax, 2
          add rbx, 2
          jmp strilcmp64w_loop
          
          strilcmp64w_exit:
          mov ax, [rax]
          sub ax, [rbx]
          and rax, 0xFFFF
          
          pop rbx
          add rsp, 0x10
          ret
          
          load_export_64:
          sub rsp, 0x20
          push rdi
          push rax
          
          xor rax, rax
          mov ax, word [rdx] ;*ordinal
          shl rax, 2     ;*ordinal * 4
          add rax, r8   ;*ordinal * 4 + base + exportsDir->AddressOfFunctions
          mov eax, dword [rax] ;RVA
          add rax, r9  ;dll base
          
          mov qword [rcx], rax
          
          pop rax
          pop rdi
          add rsp, 0x20
          ret
          Ответить
          • Писалось всё полностью вручную.
            Ответить
          • А что за асм такой хуёвый что приходится юзать db для банального mov?
            Ответить
            • Какая-то из версий «Fasm'а» почему-то конпелировала «mov rdx, qword [gs:0x60]» в херню. Или я неправильно что-то делал, забыл уже за давностью лет.
              Ответить

    Добавить комментарий