最近在浏览一篇文章的时候,偶然看见了一篇由readteam工具开发人员写的开发日志,较为详细地描述了自己是如何绕过AV,并且将部分代码贴了出来,直接从 c++ 反转 Ntdll.dll 和硬编码系统调用。
- 反编译NtCreateFile 和 NtWriteFile 函数并找到系统调用。
- 创建函数原型
- 对函数系统调用进行硬编码。
- 使用 main 和 All done 中的功能。
反编译NtCreateFile 和NtWriteFile 函数并找到系统调用
首先打开您的 IDA 并从 c:\windows\syswow64\ntdll.dll 拖放 Ntdll.dll,然后确保您导入 idb 文件。
下一步转到 Exports 点击并搜索 Ntcreatefile函数
mov eax, 55h ; 'U' ; NtCreateFile
mov edx, offset _Wow64SystemServiceCall@0 ; Wow64SystemServiceCall()
call edx ; Wow64SystemServiceCall() ; Wow64SystemServiceCall()
retn 2Ch ; ','
move eax,55h
其中55 是 NtCreateFile 函数的系统调用号,因为我们是 64 位系统,我们的应用程序是 86 位,所以我们需要切换到 wow64 位。我们需要对这个 asm 代码做一些更改,要做的使用 call dword ptr fs :[0xC0]
将它手动切换到syswow64
,所以对应的代码如下:
mov eax,55h
call dword ptr fs:[0xC0] ; wow64cpu.dll!X86SwitchTo64BitMode
retn 2Ch
现在我们有了 NtcreateFile 的 asm 代码,现在对 NtwriteFile 函数执行相同的操作。
因为我们正在使用 Nt 函数并且我们正在硬编码,所以我们需要注意的每一件事,我们要注意我们要写入它的文件路径。如果我们使用 Winapi
并且需要使用 CreateFileA
或 CreateFileW
创建文件,则路径将是这样的:c:\users\mose3c\Desktop\my.jpg
并且 winapi 函数将为您完成所有事情,例如将路径转换为 Nt Path 。如果您打开 ApiMonotring 并跟踪 CreateFile 函数,您可以仔细看到这一点,您将知道该函数为您做了什么。
现在我们的 Nt 路径将是这样的: \??\c:\users\mose3c\Desktop\my.jpg
,否则无法正常工作。
创建函数原型
typedef _Return_type_success_(return >= 0) LONG NTSTATUS;
typedef struct _STRING { USHORT Length; USHORT MaximumLength; PCHAR Buffer; } STRING;
typedef STRING* PSTRING;
typedef STRING ANSI_STRING;
typedef PSTRING PANSI_STRING;
typedef struct _UNICODE_STRING
{
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, * PUNICODE_STRING;
typedef struct _OBJECT_ATTRIBUTES
{
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES;
typedef struct _IO_STATUS_BLOCK
{
union
{
NTSTATUS Status;
VOID* Pointer;
};
ULONG_PTR Information;
} IO_STATUS_BLOCK, * PIO_STATUS_BLOCK;
typedef NTSTATUS(NTAPI* _RtlGetVersion)(PRTL_OSVERSIONINFOW lpVersionInformation);
typedef void (NTAPI* _RtlInitUnicodeString)(PUNICODE_STRING DestinationString, PCWSTR SourceString);
typedef DWORD(NTAPI* _RtlAnsiStringToUnicodeString)(PUNICODE_STRING, PANSI_STRING, BOOL);
typedef VOID(NTAPI* _RtlInitString)(PSTRING DestinationString, char* SourceString);
_RtlAnsiStringToUnicodeString RtlAnsiStringToUnicodeString = (_RtlAnsiStringToUnicodeString)GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlAnsiStringToUnicodeString");
_RtlInitUnicodeString RtlInitUnicodeString = (_RtlInitUnicodeString)GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlInitUnicodeString");
_RtlInitString RtlInitString = (_RtlInitString)GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlInitString");
typedef VOID(NTAPI* PIO_APC_ROUTINE)(_In_ PVOID ApcContext, _In_ PIO_STATUS_BLOCK IoStatusBlock, _In_ ULONG Reserved);
typedef NTSTATUS(NTAPI* _NtCreateFile)(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize OPTIONAL, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer OPTIONAL, ULONG EaLength);
typedef NTSTATUS(NTAPI* _NtWriteFile)(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key);
typedef NTSTATUS(NTAPI* _NtResumeThread)(HANDLE ThreadHandle, PULONG SuspendCount);
typedef NTSTATUS(NTAPI* _NtClose)(HANDLE Handle);
_NtCreateFile NtCreateFile;
_NtWriteFile NtWriteFile;
_NtResumeThread NtResumeThread;
_NtClose NtClose;
now lets write our inline asm code .
_declspec(naked) NTSTATUS _stdcall WIN10_64_NtCreateFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize OPTIONAL, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer OPTIONAL, ULONG EaLength)
{
_asm
{
mov eax, 55h
call dword ptr fs : [0xC0]
retn 2Ch
}
}
_declspec(naked) NTSTATUS _stdcall WIN10_64_NtWriteFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key)
{
_asm
{
mov eax, 1A0008h
call dword ptr fs : [0xC0]
retn 24h
}
}
做好这些后,接下来让我们进入我们的最主要的步骤:
我们需要将 WIN10_64_NtCreateFile
= 的地址传递给 NtCreateFile
和 WIN10_64_NtWriteFile
的地址传递给 NtWriteFile
,例如以下代码
NtCreateFile = &WIN10_64_NtCreateFile
NtWriteFile = &WIN10_64_NtWriteFile
ok . and now we will define attributes and others args but its not our tutorial will skip it and if you need any help just replay and i will try to help you .
NTSTATUS status;
UNICODE_STRING Ustring;
ANSI_STRING as;
HANDLE hFile;
IO_STATUS_BLOCK risb;
OBJECT_ATTRIBUTES robj;
char szDir[MAX_PATH];
strcpy(szDir, "\\??\\c:\users\mose3c\Desktop\my.txt");
as.Buffer = (char*)malloc(strlen(szDir) + 1);
strcpy(as.Buffer, szDir);
as.Length = as.MaximumLength = Ustring.MaximumLength = Ustring.Length = strlen(szDir);
// convert directory name from ANSI to UNICODE
_RtlAnsiStringToUnicodeString RtlAnsiStringToUnicodeString = (_RtlAnsiStringToUnicodeString)GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlAnsiStringToUnicodeString");
RtlAnsiStringToUnicodeString(&Ustring, &as, TRUE);
RtlFillMemory(&obj, sizeof(OBJECT_ATTRIBUTES), 0);
robj.Length = sizeof(obj);
robj.Attributes = OBJ_CASE_INSENSITIVE;
robj.RootDirectory = NULL;
robj.SecurityDescriptor = NULL;
robj.SecurityQualityOfService = NULL;
robj.ObjectName = &Ustring;
status = NtCreateFile(&hFile, FILE_GENERIC_READ | FILE_GENERIC_WRITE | SYNCHRONIZE, &obj, &risb, 0, FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (!NT_SUCCESS(status))
return 1 ;
IO_STATUS_BLOCK WFISB;
status = NtWriteFile(hFile, NULL, NULL, NULL, &WFISB, /*your Buffer here*/, BufLen, 0, NULL);
if (!NT_SUCCESS(status))
return 1;
搞定以上内容后,在WIN10就可以运行了,如果需要在
Windows 7中运行,需要手动反编译Windows 7
的ntdll.dll
,并且找到相关的API
I always spent my half an hour to read this web site’s content daily along with a cup of coffee.