• XSS.stack #1 – первый литературный журнал от юзеров форума

NtCreateFile возвращает C000000D

sosaaaa1337

RAID-массив
Пользователь
Регистрация
18.07.2021
Сообщения
73
Реакции
10
Депозит
0.02
Здравствуйте. при написании такого кода на ФАСМе крейт файл ругается на параметры и выдает C000000D:
Код:
format PE64 Console 5.0
entry Start
include 'win64ax.inc'
struct _OBJECT_ATTRIBUTES
    Length dd 0
    RootDirectory dq 0
    ObjectName dq 0
    Attributes dd 0
    DSecurityDescriptor dq 0
    SecurityQualityOfService dq 0
ends
struct _UNICODE_STRING
      Length dw  0
      MaximumLength dw 0
      Buffer dq  0
ends
section '.text' code readable executable

Start:
    push    rsi          
    mov        rsi, rsp
    and        rsp, 0FFFFFFFFFFFFFFF0h  
  sub        rsp, 020h      
    call    main  
    mov        rsp, rsi
    pop        rsi
  ret
filename db '\',0,'?',0,'?',0,'\',0,'C',0,':',0,'\',0,'X',0,'e',0,'r',0,'o',0,'x',0,'\',0,'g',0,'a',0,'g',0,'a',0,'.',0,'e',0,'x',0,'e',0,0,0
  namelenmax = $-filename
 proc main
 local objattrproc2:_OBJECT_ATTRIBUTES
 local unistring:_UNICODE_STRING
 local handlefile dq 0
 local iostatus dq 2 dup(0)
 mov bx, namelenmax
 mov [unistring.MaximumLength], bx
 sub bx, 2
 mov [unistring.Length], bx
 lea rbx, [filename]
 mov [unistring.Buffer], rbx
 mov [objattrproc2.Length], 48
 mov [objattrproc2.Attributes], 0
 mov [objattrproc2.RootDirectory], 0
 mov [objattrproc2.DSecurityDescriptor], 0
 mov [objattrproc2.SecurityQualityOfService],0
 lea rbx, [unistring]
 mov [objattrproc2.ObjectName], rbx
 lea rcx, [handlefile]
 mov rdx, 80000h
 lea r8, [objattrproc2]
 lea r9, [iostatus]
 sub rsp, 58h
 mov qword [rsp+20h], 0
  mov qword [rsp+28h], 0
  mov qword [rsp+30h], 0
  mov qword [rsp+38h], 1
  mov qword [rsp+40h], 0
  mov qword [rsp+48h], 0
  mov qword [rsp+50h], 0
  call NtCreateFile
 ret
 endp
 proc NtCreateFile PHANDLEFileHandle,\
  ACCESS_MASKDesiredAccess,            \
  POBJECT_ATTRIBUTESObjectAttributes,          \
  PIO_STATUS_BLOCKIoStatusBlock,              \
  PLARGE_INTEGERAllocationSize,              \
  ULONGFileAttributes,               \
  ULONGShareAccess,                   \
  ULONGCreateDisposition,              \
  ULONGCreateOptions,                   \
  PVOIDEaBuffer,                         \
  ULONGEaLength                    
mov r10, rcx
mov rax, 55h
syscall
ret
endp
Но при этом код из студии работает хорошо:
C:
#include <Windows.h>
#include <stdio.h>
struct IO_STATUS {
    ULONG_PTR a;
    ULONG_PTR b;
};
typedef struct _UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
#ifdef MIDL_PASS
    [size_is(MaximumLength / 2), length_is((Length) / 2)] USHORT* Buffer;
#else // MIDL_PASS
    _Field_size_bytes_part_opt_(MaximumLength, Length) PWCH   Buffer;
#endif
} UNICODE_STRING;
typedef struct _OBJECT_ATTRIBUTES {
    ULONG Length;
    HANDLE RootDirectory;
    UNICODE_STRING* ObjectName;
    ULONG Attributes;
    PVOID SecurityDescriptor;      
    PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES;
typedef OBJECT_ATTRIBUTES* POBJECT_ATTRIBUTES;
typedef DWORD(WINAPI* NtCreateFile)(PHANDLE            FileHandle, ACCESS_MASK        DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, IO_STATUS*   IoStatusBlock, PLARGE_INTEGER     AllocationSize, ULONG              FileAttributes, ULONG              ShareAccess, ULONG              CreateDisposition, ULONG              CreateOptions, PVOID              EaBuffer, ULONG              EaLength);
int main()
{
    IO_STATUS iobl = { 0 };
    HANDLE flhnd = 0;
    HMODULE nt = LoadLibraryW(L"ntdll.dll");
    NtCreateFile crtfl = (NtCreateFile)GetProcAddress(nt, "NtCreateFile");
    UNICODE_STRING unistr = { 0 };
    unistr.Buffer = (PWSTR)L"\\??\\C:\\Xerox\\gaga.exe";
    unistr.Length = 42;
    unistr.MaximumLength = 44;
    OBJECT_ATTRIBUTES objattr = { 0 };
    objattr.Length = sizeof(objattr);
    objattr.RootDirectory = 0;
    objattr.ObjectName = &unistr;
    objattr.Attributes = 0;
    objattr.SecurityDescriptor = 0;
    objattr.SecurityQualityOfService = 0;
    DWORD status = crtfl(&flhnd, WRITE_OWNER, &objattr, &iobl, 0, 0, 0, 1, 0, 0, 0);
    printf("%x status", status);
    getchar();
    return(0);
}
я залез в отладчик и увидел, что компиляторы выравнивают поля в структурах по-разному, приложу пикчи заполненной структуры unicode_string в фасме и в visual studio.
почему так? visual studio меняет смещение полей в структуре? как сделать так, чтобы системный вызов крейт файла возвращал status_success? спасибо за внимание.
 

Вложения

  • allin1.PNG
    allin1.PNG
    5.5 КБ · Просмотры: 39
  • visualsend.png
    visualsend.png
    5.2 КБ · Просмотры: 37
Последнее редактирование:
Окей, тут есть несколько проблем


1)

Код:
proc NtCreateFile PHANDLEFileHandle,\
  ACCESS_MASKDesiredAccess,            \
  POBJECT_ATTRIBUTESObjectAttributes,          \
  PIO_STATUS_BLOCKIoStatusBlock,              \
  PLARGE_INTEGERAllocationSize,              \
  ULONGFileAttributes,               \
  ULONGShareAccess,                   \
  ULONGCreateDisposition,              \
  ULONGCreateOptions,                   \
  PVOIDEaBuffer,                         \
  ULONGEaLength                  
mov r10, rcx
mov rax, 55h
syscall
ret
endp

Макросы
Код:
proc/endp
генерят пролог и эпилог, то есть при компиляции ты получишь перед
Код:
mov r10, rcx
следующую конструкцию:
Код:
push rbp
mov rbp,rsp

что сдвинет стек и занулит например CreateDisposition параметр что уже факапит логику.
Я бы сделал просто вот так:

Код:
NtCreateFile:
mov r10, rcx
mov rax, 55h
syscall
ret

^ То есть просто как метку


2) Выравнивание структур. Все структуры должны быть выровнены по 8ми байтам, если этого не сделать то обработчик сиськи в ядре неверно прочитает переданные в структурах параметры.

Например:

Код:
struct _UNICODE_STRING
      Length dw  0
      MaximumLength dw 0
      Buffer dq  0
ends

Тут получается что размер структуры - 12 байт ( не выровнено!! ) и оффсет буфера _UNICODE_STRING+4. А обработчик в ядре читает буфер отсюда: UNICODE_STRING+8 ибо структура должна выровнена быть

Соответсвенно меняем определение уникодового стринга:

Код:
struct _UNICODE_STRING
      Length dw  0
      MaximumLength dw 0
      dd 0                    ; <-- Добиваем тут 4 байта чтобы выровнять размер структуры
      Buffer dq  0
ends

И теперь оффсет где лежит буффер будет верный. Аналогично добиваем _OBJECT_ATTRIBUTES:

Код:
struct _OBJECT_ATTRIBUTES
    Length dd 0
           dd 0 ;<- добиваем до 8ми байт
    RootDirectory dq 0
    ObjectName dq 0
    Attributes dd 0
               dd 0 ;<- добиваем до 8ми байт
    DSecurityDescriptor dq 0
    SecurityQualityOfService dq 0
ends

Вот собственно и всё.
 
Если используете FASM не забывайте про банальный invoke или stdcall, также есть frame для избавления от ебанины в виде "sub rsp, 58h" перед call в х64, там кстати после надо "add rsp, 58h" делать, если ручками.

Код:
filename db '\',0,'?',0,'?',0,'\',0,'C',0,':',0,'\',0,'X',0,'e',0,'r',0,'o',0,'x',0,'\',0,'g',0,'a',0,'g',0,'a',0,'.',0,'e',0,'x',0,'e',0,0,0

Unicode-строки можно через du оформлять:

Код:
filename du "\??\C:\X0e0r0..",0
 
как сделать так, чтобы системный вызов крейт файла возвращал status_success?
Помимо выравнивания структур в памяти, имеется ещё и глюк самих инструкций syscall/sysret на процессорах AMD. Проблема в том, что селектор сегмента стека в SS сбрасывается в нуль, поэтому нужно перед syscall сохранять SS:RSP, а после (до ret в процедуре) опять восстанавливать их. Здесь недавно мы обсуждали этот вопрос: https://wasm.in/threads/problemy-s-ret-far.34887/
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх