DO NOT DEAL WITH THIS MEMBER
Apr 1, 2024 08:17 PM
(This post was last modified: Mar 16, 2026 08:24 AM by Hackers.)
Hi all, this thread is about using hashes instead of literal string names to call functions in Windows, typedefs, base addresses, and general function wrapping. Specifically, I'll share some funcs from Ntdll that I have setup to be called by their hash rather than their traditional name - focusing on NtCreateFile as an example of a way to "skip" a traditional windows API func. I will be sharing some code snippets and mentioning some steps I took, but this is not a full source or program release ~ just a discussion thread with some examples :)
Have any of you done anything similar? It is said that it may help keep your programs secure by making them slightly harder to RE/analyze. I am still just making use of this hashed names technique, but it's hard to assess its effectiveness due to the high number of other unique methods in use - peb/teb walking, ntdll loading, etc.
Before I start - if you do not know about PEB, TEB, or Ntdll function loading, I recommend jumping into my thread about this topic here:
https://hackforums.net/showthread.php?tid=6266052
Define the type first - you must do this for any function you would use like this.
Code typedef NTSTATUS(NTAPI* NTCREATEFILE)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG);
Define the hash:
Code #define NTCREATEFILE_SIG 0x15a5ecdb
Now, how did I get this hash, and what is it? It is generated with djb2, a very simple hashing function.
Code unsigned long djb2(unsigned char* str) {
unsigned long hash = 5381;
int c;
while ((c = *str++))
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash;
}
Truth be told, I had used another codebase for reference that had 2 ntdll functions loaded in with this hashing algorithm in use already, so I went ahead with that. However, I needed a way to get the hashes, and I simultaneously wanted an easy way to generate the many definitions I would need...
I wrote a mini C++ program that iterates over function names, finds their djb2 hash, and then prints out a list of #define statements for me to copy into my other program!
Code #include <stdio.h>
#include <string.h>
unsigned long djb2(unsigned char* str) {
unsigned long hash = 5381;
int c;
while ((c = *str++))
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash;
}
int main() {
// Change to const char* to match the type of string literals
const char* functions[] = {
"NtAllocateVirtualMemory",
"NtFreeVirtualMemory",
"NtWriteVirtualMemory",
"NtReadVirtualMemory",
"NtCreateFile",
"NtClose",
"NtQueryInformationProcess",
"NtSetInformationProcess",
"NtQuerySystemInformation",
"NtSetSystemInformation",
"NtQueryInformationThread",
"NtSetInformationThread",
"NtOpenProcess",
"NtTerminateProcess",
"NtCreateThreadEx",
"NtTerminateThread",
"NtOpenThread",
"NtDelayExecution",
"NtYieldExecution",
"NtWaitForSingleObject",
"NtWaitForMultipleObjects",
"NtCreateEvent",
"NtSetEvent",
"NtResetEvent",
"NtClearEvent",
"NtCreateMutant",
"NtReleaseMutant",
"NtCreateSemaphore",
"NtReleaseSemaphore",
"NtQueryVirtualMemory",
"NtProtectVirtualMemory",
NULL // Marks the end of the array
};
for (int i = 0; functions[i] != NULL; i++) {
// Casting to unsigned char* is needed due to the function parameter type
printf("#define %s_SIG 0x%lx\n", functions[i], djb2((unsigned char*)functions[i]));
}
return 0;
}
Simple & effective. I can add other functions I need as I see fit in the future.
One benefit of this codebase I'm working on is the use of the Api class that helps wrap all of my funcs. I have some funcs from the win32 lib here as well as ntdll.
Remember though, you must define each function / type in your source!
In order to use any function in my code, I must also add it to the api import table so that my program knows what to get from each lib. I have snipped/removed some code from this next segment so its easy to see what I've done for NtCreateFile:
Code typedef struct API_IMPORT_TABLE {
DWORD64 PeBase;
DWORD64 Win32uBase;
PPEB Peb;
PTEB Teb;
LDRLOADDLL LdrLoadDll;
NTCREATEFILE NtCreateFile;
NTALLOCATEVIRTUALMEMORY NtAllocateVirtualMemory;
NTFREEVIRTUALMEMORY NtFreeVirtualMemory;
NTWRITEVIRTUALMEMORY NtWriteVirtualMemory;
NTCLOSE NtClose;
NTWRITEFILE NtWriteFile;
NTQUERYINFORMATIONFILE NtQueryInformationFile;
NTSETINFORMATIONFILE NtSetInformationFile;
} API_TABLE, * PAPI_TABLE;
Now, in a separate place in code we must actually import the function, set it to our custom type, using our hash (SIG) to name the function, based on our current PE's base address:
Code Api.NtCreateFile = (NTCREATEFILE)ImportFunction(Api.PeBase, NTCREATEFILE_SIG);
It uses an initialize function to load up all of the ntdll related funcs:
The code so far is fairly flexible and reliable as long as the core base addresses can be found. I'm on Windows 11 with this one and have not yet tested it on older machines.
Here's the start of my main func that finds the current teb & peb and then loads in the ntdll funcs using our initialization function from above.
Code Api.Teb = (PTEB)GetTeb();
Api.Peb = (PPEB)Api.Teb->ProcessEnvironmentBlock;
PLDR_MODULE LoaderModule = NULL;
if (Api.Peb->OSMajorVersion != 0x0a){
return ERROR_CALL_NOT_IMPLEMENTED;
}
LoaderModule = (PLDR_MODULE)((PBYTE)Api.Peb->LoaderData->InMemoryOrderModuleList.Flink->Flink - 16);
Api.PeBase = (DWORD64)LoaderModule->BaseAddress;
if (!LdrLoadNtDllFunctionality()){
return ERROR_INVALID_FUNCTION;
}
LdrLoadNtDllFunctionality imports all of our funcs, and then we can use it however we like!
Usage example:
Code Status = Api.NtCreateFile(&hHandle, FILE_GENERIC_WRITE | FILE_GENERIC_READ, &Attributes, &Io, &Integer, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN_IF, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, 0, 0);
if (!NT_SUCCESS(Status)){
return NULL;
}
All in all, I am looking for other devs who have experience with PEB/TEB, Nt, Rtl, and Zw functions as replacements for native Windows API calls, and I'd love to learn more. I hope that what I have shared today is helpful or can at very least start some HQ discussions in replies!.
Disclaimer:
This code is based on code found in another tool. I removed the core functionality (logging) from the other program to keep their PEB/TEB functions & also the start of their Ntdll wrappers. I then started working on bringing over more ntdll functions, which is why I wrote the program to get more hashes for the names and added more typedefs, etc.
Again - My code contains 0 functionality related to keylogging - This program however has some good examples for PEB/TEB/Nt wrapper funcs:
Code https://github.com/vxunderground/VXUG-Papers/blob/main/NtUserGetRawInputDataKeylogger.cpp
good resource, this is extremely important to understand when working with encryption.
There are a few winapi functions you can modify for a more stealthy approach, for example obfuscating parts of the table and using different winapi methods:
Code typedef struct {
DWORD64 BaseAddress;
DWORD64 GraphicsBase;
PPEB ProcessEnvironmentBlock;
PTEB ThreadEnvironmentBlock;
PVOID LoadLibraryFunc;
PVOID CreateFileFunc;
PVOID AllocateMemoryFunc;
PVOID FreeMemoryFunc;
PVOID WriteMemoryFunc;
PVOID CloseHandleFunc;
PVOID WriteFileFunc;
PVOID QueryFileInfoFunc;
PVOID SetFileInfoFunc;
} OBFUSCATED_TABLE, * POBFUSCATED_TABLE;
POBFUSCATED_TABLE InitializeObfuscatedTable() {
POBFUSCATED_TABLE table = (POBFUSCATED_TABLE)malloc(sizeof(OBFUSCATED_TABLE));
if (table == NULL) {
return NULL;
}
HMODULE ntdll = LoadLibraryA(DecryptString("encrypted_ntdll.dll"));
table->CreateFileFunc = GetProcAddress(ntdll, DecryptString("encrypted_NtCreateFile"));
// Repeat for other functions
return table;
}
char* DecryptString(char* encryptedString) {
// Implement string decryption logic here
return encryptedString; // Placeholder
}
DO NOT DEAL WITH THIS MEMBER
(Apr 3, 2024 05:30 PM)PulseLink Wrote: good resource, this is extremely important to understand when working with encryption.
There are a few winapi functions you can modify for a more stealthy approach, for example obfuscating parts of the table and using different winapi methods:
Code typedef struct {
DWORD64 BaseAddress;
DWORD64 GraphicsBase;
PPEB ProcessEnvironmentBlock;
PTEB ThreadEnvironmentBlock;
PVOID LoadLibraryFunc;
PVOID CreateFileFunc;
PVOID AllocateMemoryFunc;
PVOID FreeMemoryFunc;
PVOID WriteMemoryFunc;
PVOID CloseHandleFunc;
PVOID WriteFileFunc;
PVOID QueryFileInfoFunc;
PVOID SetFileInfoFunc;
} OBFUSCATED_TABLE, * POBFUSCATED_TABLE;
POBFUSCATED_TABLE InitializeObfuscatedTable() {
POBFUSCATED_TABLE table = (POBFUSCATED_TABLE)malloc(sizeof(OBFUSCATED_TABLE));
if (table == NULL) {
return NULL;
}
HMODULE ntdll = LoadLibraryA(DecryptString("encrypted_ntdll.dll"));
table->CreateFileFunc = GetProcAddress(ntdll, DecryptString("encrypted_NtCreateFile"));
// Repeat for other functions
return table;
}
char* DecryptString(char* encryptedString) {
// Implement string decryption logic here
return encryptedString; // Placeholder
}
You can do what you've done, but in my opinion it's better to get ntdll from the current PEB and get the more obscure loader funcs to then load any libraries. You can use ntdll functions without needing to use LoadLibraryA there, or get proc address.
I still think it's good that you've shared this though - cheers.
(Apr 3, 2024 05:33 PM)Hackers Wrote: You can do what you've done, but in my opinion it's better to get ntdll from the current PEB and get the more obscure loader funcs to then load any libraries. You can use ntdll functions without needing to use LoadLibraryA there, or get proc address.
I still think it's good that you've shared this though - cheers.
I agree completely, I was pointing out some functions could be further obfuscated.
You can use NtDll without DIRECTLY invoking any functions if you really wanted to:
Instead of NtCreateFile, use CreateFile or CreateFileEx.
Instead of NtAllocateVirtualMemory, use VirtualAlloc or VirtualAllocEx.
but in this case theres no real reason not to just directly call it.
Ty again for sharing, seems these topics need more eyes on them as its important for further understanding/development
DO NOT DEAL WITH THIS MEMBER
Apr 10, 2024 06:05 AM
(This post was last modified: Apr 10, 2024 06:05 AM by Hackers.)
(Apr 3, 2024 05:45 PM)PulseLink Wrote: I agree completely, I was pointing out some functions could be further obfuscated.
You can use NtDll without DIRECTLY invoking any functions if you really wanted to:
Instead of NtCreateFile, use CreateFile or CreateFileEx.
Instead of NtAllocateVirtualMemory, use VirtualAlloc or VirtualAllocEx.
but in this case theres no real reason not to just directly call it.
Ty again for sharing, seems these topics need more eyes on them as its important for further understanding/development
Is there a reason to use CreateFile or CreateFileEx, or VirtualAlloc/ex or other similar funcs instead of the Nt, Zw, or Rtl functions?
AFAIK using the Nt functions is more secretive than using their wrapper functions instead? I've noticed that when I use the Nt functions for example, I get less detections than if I don't. This to me makes me think that the opposite of what you are saying is true, but if you have info on why you would not want to use Nt functions please let me know.
Apr 10, 2024 02:48 PM
(This post was last modified: Apr 11, 2024 01:31 AM by InvizCustos.)
(Apr 3, 2024 05:30 PM)PulseLink Wrote: good resource, this is extremely important to understand when working with encryption.
There are a few winapi functions you can modify for a more stealthy approach, for example obfuscating parts of the table and using different winapi methods:
Code typedef struct {
DWORD64 BaseAddress;
DWORD64 GraphicsBase;
PPEB ProcessEnvironmentBlock;
PTEB ThreadEnvironmentBlock;
PVOID LoadLibraryFunc;
PVOID CreateFileFunc;
PVOID AllocateMemoryFunc;
PVOID FreeMemoryFunc;
PVOID WriteMemoryFunc;
PVOID CloseHandleFunc;
PVOID WriteFileFunc;
PVOID QueryFileInfoFunc;
PVOID SetFileInfoFunc;
} OBFUSCATED_TABLE, * POBFUSCATED_TABLE;
POBFUSCATED_TABLE InitializeObfuscatedTable() {
POBFUSCATED_TABLE table = (POBFUSCATED_TABLE)malloc(sizeof(OBFUSCATED_TABLE));
if (table == NULL) {
return NULL;
}
HMODULE ntdll = LoadLibraryA(DecryptString("encrypted_ntdll.dll"));
table->CreateFileFunc = GetProcAddress(ntdll, DecryptString("encrypted_NtCreateFile"));
// Repeat for other functions
return table;
}
char* DecryptString(char* encryptedString) {
// Implement string decryption logic here
return encryptedString; // Placeholder
}
You can simply use an off-the-shelf solution:
https : //github.com/JustasMasiulis/lazy_importer
This library does not use winapi and only works with PEB
DO NOT DEAL WITH THIS MEMBER
Apr 10, 2024 03:06 PM
(This post was last modified: Apr 10, 2024 06:41 PM by Hackers.)
(Apr 10, 2024 02:48 PM)InvizCustos Wrote: You can simply use an off-the-shelf solution:
https : //github.com/JustasMasiulis/lazy_importer
No use of winapi, only working with PEB I originally thought you were replying to me, but see you replied to PulseLink.
Agreed - it's better to work with PEB & Ntdll and never use LoadLibrary / similar win api functions in my opinion.
Apr 19, 2024 11:28 AM
(This post was last modified: Apr 19, 2024 12:12 PM by dasdas543534534.)
(Apr 10, 2024 03:06 PM)Hackers Wrote: I originally thought you were replying to me, but see you replied to PulseLink.
Agreed - it's better to work with PEB & Ntdll and never use LoadLibrary / similar win api functions in my opinion.
This is very, very wrong. Please go ahead and explore the world of EDR's before making such statements.
This statement was right maybe 8-10 years ago, AV's has since evolved.
If anything, it almost flags you because I am not aware of any whitehat software that uses the "PEB" to obtain an address of a function. (You can test Avira runtime on clean scantime with only a PEB walk)
Now let's assume you chose this path, what does it help you with if you aren't flagged? Ring 3 protection is implemented by EDR vendors and antivirus software using the Nt* functions, thus you will still be "heuristically" checked at runtime. You neither help yourself nor save anything.
The only correct approach is direct syscalls with SYSCALL ID manipulation, anything else is just... waste of time detection wise, maybe makes it 2 seconds harder for any novice reverse engineer.
(Apr 3, 2024 05:30 PM)PulseLink Wrote: good resource, this is extremely important to understand when working with encryption.
There are a few winapi functions you can modify for a more stealthy approach, for example obfuscating parts of the table and using different winapi methods:
Code typedef struct {
DWORD64 BaseAddress;
DWORD64 GraphicsBase;
PPEB ProcessEnvironmentBlock;
PTEB ThreadEnvironmentBlock;
PVOID LoadLibraryFunc;
PVOID CreateFileFunc;
PVOID AllocateMemoryFunc;
PVOID FreeMemoryFunc;
PVOID WriteMemoryFunc;
PVOID CloseHandleFunc;
PVOID WriteFileFunc;
PVOID QueryFileInfoFunc;
PVOID SetFileInfoFunc;
} OBFUSCATED_TABLE, * POBFUSCATED_TABLE;
POBFUSCATED_TABLE InitializeObfuscatedTable() {
POBFUSCATED_TABLE table = (POBFUSCATED_TABLE)malloc(sizeof(OBFUSCATED_TABLE));
if (table == NULL) {
return NULL;
}
HMODULE ntdll = LoadLibraryA(DecryptString("encrypted_ntdll.dll"));
table->CreateFileFunc = GetProcAddress(ntdll, DecryptString("encrypted_NtCreateFile"));
// Repeat for other functions
return table;
}
char* DecryptString(char* encryptedString) {
// Implement string decryption logic here
return encryptedString; // Placeholder
}
2008 approach. There is no need for any of this shit in modern c++ with templates as was stated earlier.
DO NOT DEAL WITH THIS MEMBER
Apr 19, 2024 12:16 PM
(This post was last modified: Apr 19, 2024 12:18 PM by Hackers.)
(Apr 19, 2024 11:28 AM)dasdas543534534 Wrote: This is very, very wrong. Please go ahead and explore the world of EDR's before making such statements.
This statement was right maybe 8-10 years ago, AV's has since evolved.
If anything, it almost flags you because I am not aware of any whitehat software that uses the "PEB" to obtain an address of a function. (You can test Avira runtime on clean scantime with only a PEB walk)
Now let's assume you chose this path, what does it help you with if you aren't flagged? Ring 3 protection is implemented by EDR vendors and antivirus software using the Nt* functions, thus you will still be "heuristically" checked at runtime. You neither help yourself nor save anything.
The only correct approach is direct syscalls with SYSCALL ID manipulation, anything else is just... waste of time detection wise, maybe makes it 2 seconds harder for any novice reverse engineer.
2008 approach. There is no need for any of this shit in modern c++ with templates as was stated earlier.
I am always open to being educated, so please provide some knowledge if you think I am incorrect here.
I got way better scores using PEB / Ntdll so unless you can show me how I'm wrong, I don't see the issue. Across the board, the peb/ntdll methods increased protections & data privacy in my programs - no question about that.
Again, you are a very toxic individual. But good luck here, I'm sure you are very fun at parties.
Apr 19, 2024 11:11 PM
(This post was last modified: Apr 19, 2024 11:14 PM by ttbr0.)
(Apr 19, 2024 12:16 PM)Hackers Wrote: I am always open to being educated, so please provide some knowledge if you think I am incorrect here.
I got way better scores using PEB / Ntdll so unless you can show me how I'm wrong, I don't see the issue. Across the board, the peb/ntdll methods increased protections & data privacy in my programs - no question about that.
Again, you are a very toxic individual. But good luck here, I'm sure you are very fun at parties.
oh boy theres a lot to unpack here so here are my thoughts...
i dont believe there are many "right or wrong" choices when it comes to this because things are never so black and white - they just have their own unique advantages and disadvantages. while dasdas543534534 is correct that antiviruses may (not all of them do) hook function calls for api monitoring, calling directly to native functions could be subjected to antivirus detection (not all of them hook at the native function level but most do) - see my thread on antivirus detection and evasion fundamentals showing sophos av hooking NtWriteVirtualMemory (shameless plug). this is a critical point that evasive malware should step around but it may not have occurred to you yet in your current research stage and i didnt want to say anything because i believe experience is the best teacher.
there is nothing "wrong" with manual PEB and export table parsing, it is an older technique that has stood the test of time and is still quite common from what i understand (see havoc framework). from what i can remember, it is pretty close to how LoadLibrary and GetProcAddress work internally anyway. while your research was good and in the right direction, you simply missed the api monitoring issues which can be dealt with quite trivially, but beware any potential traps or defense mechanisms.
while direct syscalls completely evades the api monitoring problem it has some of its own issues such as scalability, incompatibility across multiple versions of windows or needing to allocate unbacked rx memory sections or originating from an unknown region from the perspective of the call stack. there are workarounds for all of these problems of course.
my point is use what you think is more suitable to your needs. i think it is unwise to discount anything unless its really infeasible.
DO NOT DEAL WITH THIS MEMBER
(Apr 19, 2024 11:11 PM)ttbr0 Wrote: there is nothing "wrong" with manual PEB and export table parsing, it is an older technique that has stood the test of time and is still quite common from what i understand (see havoc framework). from what i can remember, it is pretty close to how LoadLibrary and GetProcAddress work internally anyway. while your research was good and in the right direction, you simply missed the api monitoring issues which can be dealt with quite trivially, but beware any potential traps or defense mechanisms.
while direct syscalls completely evades the api monitoring problem it has some of its own issues such as scalability, incompatibility across multiple versions of windows or needing to allocate unbacked rx memory sections or originating from an unknown region from the perspective of the call stack. there are workarounds for all of these problems of course.
my point is use what you think is more suitable to your needs. i think it is unwise to discount anything unless its really infeasible.
It definitely is older and more documented, but I guess the problem I'm having is that it feels like LoadLibrary and GetProcAddress are just as easily detectable, and undetectable as Nt, Zw, and Rtl functions? I understand that PEB & those may have signature detections, but wouldn't the alternatives also have signatures by now? Either way, definitely will loop back around and re-research. The problem I had was that things like loadlibrary & getprocaddress specifically seemed to be much more detected. Creating wrapper functions or using the PEB to actually get the base address of loadlibrary & getprocaddress also seemed better than just using them when I was testing that. I guess this is the piece I can't wrap my head around - I understand what you are saying & the user above are saying, but how is the api monitoring different between the two methods & why is it better to use the api functions over direct peb & ntdll functions? If I converted some of the peb methods I have now back to code that uses getprocaddress and ran a scan they'd go from like a score of 10 to 25-40, so that's why it's hard for me to. It feels like I am missing something here.
For direct syscalls, that's what I ran into - it has to be system specific, but you can map a lot of things out, have version files for the OS that are either packaged in statically or downloaded in runtime. I played with a repo related to that to use syscalls across different devices.
Definitely agreed there, I basically just want to try everything. I started with loadlibrary and normal api funcs at first, then moved to peb/teb & ntdll loading, then tried out syscalls. Not sure what I'll try next, but working on some AI related C/C++ code more than this type of Windows work, at least the last couple weeks or so.
(Apr 20, 2024 04:46 AM)Hackers Wrote: It definitely is older and more documented, but I guess the problem I'm having is that it feels like LoadLibrary and GetProcAddress are just as easily detectable, and undetectable as Nt, Zw, and Rtl functions? I understand that PEB & those may have signature detections, but wouldn't the alternatives also have signatures by now? Either way, definitely will loop back around and re-research. The problem I had was that things like loadlibrary & getprocaddress specifically seemed to be much more detected. Creating wrapper functions or using the PEB to actually get the base address of loadlibrary & getprocaddress also seemed better than just using them when I was testing that. I guess this is the piece I can't wrap my head around - I understand what you are saying & the user above are saying, but how is the api monitoring different between the two methods & why is it better to use the api functions over direct peb & ntdll functions? If I converted some of the peb methods I have now back to code that uses getprocaddress and ran a scan they'd go from like a score of 10 to 25-40, so that's why it's hard for me to. It feels like I am missing something here.
For direct syscalls, that's what I ran into - it has to be system specific, but you can map a lot of things out, have version files for the OS that are either packaged in statically or downloaded in runtime. I played with a repo related to that to use syscalls across different devices.
Definitely agreed there, I basically just want to try everything. I started with loadlibrary and normal api funcs at first, then moved to peb/teb & ntdll loading, then tried out syscalls. Not sure what I'll try next, but working on some AI related C/C++ code more than this type of Windows work, at least the last couple weeks or so.
it all really depends on what you are trying to achieve. each technique was developed to solve specific problems. if you believe that compiling in or using GetProcAddress and LoadLibrary into your executable will raise unnecessary flags to scanning engines then you can use peb enumeration and export table parsing. if you want to bypass the need to tamper with api monitoring hooks then use direct syscalls.
keep in mind that you can use peb enumeration and direct syscalls together, they are not mutually exclusive. one solves the issue of discovering modules and the other bypasses api monitoring. the hells gate implementation enumerates the peb to find ntdll and then recovers the original syscall to directly invoke.
DO NOT DEAL WITH THIS MEMBER
(Apr 20, 2024 06:54 AM)ttbr0 Wrote: it all really depends on what you are trying to achieve. each technique was developed to solve specific problems. if you believe that compiling in or using GetProcAddress and LoadLibrary into your executable will raise unnecessary flags to scanning engines then you can use peb enumeration and export table parsing. if you want to bypass the need to tamper with api monitoring hooks then use direct syscalls.
keep in mind that you can use peb enumeration and direct syscalls together, they are not mutually exclusive. one solves the issue of discovering modules and the other bypasses api monitoring. the hells gate implementation enumerates the peb to find ntdll and then recovers the original syscall to directly invoke.
Gotcha gotcha
I'll be doing some blue team / detection stuff soon to see how I can detect things to better understand how an OS stays safe - I'm sure that'll make things a bit clearer. Are malware devs using the api functions because they're more normal and commonly used by whitehat? Just curious how you would go about making sure not to false-flag a safe software, like for example you can't just block software that saves files because then notepad.exe wouldn't work too well - What type of logic goes into deciding whether a program is saving data maliciously or not? I'm guessing it may be related to user actions, time, type of memory, but I really could learn more about this, so wondering how things work currently.
(Apr 20, 2024 04:46 AM)Hackers Wrote: It definitely is older and more documented, but I guess the problem I'm having is that it feels like LoadLibrary and GetProcAddress are just as easily detectable, and undetectable as Nt, Zw, and Rtl functions? I understand that PEB & those may have signature detections, but wouldn't the alternatives also have signatures by now? Either way, definitely will loop back around and re-research. The problem I had was that things like loadlibrary & getprocaddress specifically seemed to be much more detected. Creating wrapper functions or using the PEB to actually get the base address of loadlibrary & getprocaddress also seemed better than just using them when I was testing that. I guess this is the piece I can't wrap my head around - I understand what you are saying & the user above are saying, but how is the api monitoring different between the two methods & why is it better to use the api functions over direct peb & ntdll functions? If I converted some of the peb methods I have now back to code that uses getprocaddress and ran a scan they'd go from like a score of 10 to 25-40, so that's why it's hard for me to. It feels like I am missing something here.
For direct syscalls, that's what I ran into - it has to be system specific, but you can map a lot of things out, have version files for the OS that are either packaged in statically or downloaded in runtime. I played with a repo related to that to use syscalls across different devices.
Definitely agreed there, I basically just want to try everything. I started with loadlibrary and normal api funcs at first, then moved to peb/teb & ntdll loading, then tried out syscalls. Not sure what I'll try next, but working on some AI related C/C++ code more than this type of Windows work, at least the last couple weeks or so.
"I basically just want to try everything" - This explains the lack of knowledge, I am here to help.
Learn the difference between scantime/runtime.
|