If you want to know what you should not do, you can check out the drivers in this repo https://github.com/hfiref0x/KDU
@brad_H said:
Well, as i said, in this scenario lets assume that i can protect my files and processes from modification (since Iām already in kernel and we assume the attacker doesnāt have a driver, if he did then its obviously game over)
You can protect files, but you canāt actually protect your running process nearly as well as you think you can.
That said, it appears that nothing anyone here says about that is going to change your mind, so Iām out.
I am really not going to comment on stuff here, because there would be too much to say.
The least I will say @brad_H is that you are very wrong with many things, especially ObCallbacks and virtualization like VMProtect.
To answer your question:
- You can check for signed binaries in Kernel, Windows does it, always had since VISTA. Look at ci.dll exported function CiCheckSignedFile, it will do everything you want.
- You cannot āsecureā IOCTLās with this, find another method of communication, like shared mapping. Or even simpler, encrypt your data both ways.
To give you a hand, do note that ci.dll has changed a lot until Windows 10 and there is no documentation for this. You have to manually reverse the structs and function parameters, generate the .lib file and link against your driver.
dumpbin /EXPORTS c:\windows\system32\ci.dll
lib /def:ci.def /machine:x64 /out:ci.lib
Enjoy.
You can check for signed binaries in Kernel, Windows does it
The discussion here is not about whether itās possible or not, in kernel mode almost everything is possible but is it the right design choice?
Everyone here simply mentioned itās not supported, and not worth the effort required to maintain this piece of codeā¦ Supporting code that uses undocumented structures + functions that often change is not as simple as āmaking it work in a test environmentā. The signature of this function (CiCheckSignedFile) was changed multiple times, so if you use it you have to adjust your code to the OS version and also keep testing your product against insider builds to make sure the function is not changed so you donāt cause BSODsā¦
This.
@Mecanik said:
I am really not going to comment on stuff here, because there would be too much to say.The least I will say @brad_H is that you are very wrong with many things, especially ObCallbacks and virtualization like VMProtect.
To answer your question:
- You can check for signed binaries in Kernel, Windows does it, always had since VISTA. Look at ci.dll exported function CiCheckSignedFile, it will do everything you want.
- You cannot āsecureā IOCTLās with this, find another method of communication, like shared mapping. Or even simpler, encrypt your data both ways.
To give you a hand, do note that ci.dll has changed a lot until Windows 10 and there is no documentation for this. You have to manually reverse the structs and function parameters, generate the .lib file and link against your driver.
dumpbin /EXPORTS c:\windows\system32\ci.dll lib /def:ci.def /machine:x64 /out:ci.lib
Enjoy.
Doing this using the ci.dll is a very risky way of doing it considering most of it is undocumented and the structures change vastly from time to time, its basically not a possible solution for a product.
@0xrepnz said:
You can check for signed binaries in Kernel, Windows does it
The discussion here is not about whether itās possible or not, in kernel mode almost everything is possible but is it the right design choice?
Everyone here simply mentioned itās not supported, and not worth the effort required to maintain this piece of codeā¦ Supporting code that uses undocumented structures + functions that often change is not as simple as āmaking it work in a test environmentā. The signature of this function (CiCheckSignedFile) was changed multiple times, so if you use it you have to adjust your code to the OS version and also keep testing your product against insider builds to make sure the function is not changed so you donāt cause BSODsā¦
I disagree, by āsupportedā I`m sure you mean if Microsoft creates documentation and says āwe support thisā, then itās āsupportedā? Thatās not how I see it, at all.
There are literally a dozen functions inside NT that havenāt changed (much) since XP, and people still use them. In fact, is it more often better to use āundocumentedā functions/functionality for several reasons.
Instead of using the ādocumentedā GetVersion(), it is better to use RtlGetVersion() + RtlGetNtVersionNumbers(). No āmanifestā needed, no bonanza.
Another example, I use only undocumented functions and system calls in my real life applications; and they are being used by hundreds of users. I simply hate Win32 API, they are slow, can be intercepted easily, etc.
So I really disagree with this ānot supportedā bonanza, we are 2 decades away from functions listed as ādeprecatedā on Microsoft website but they are still there, they still work, and thatās that.
As for the ci.dll, the only issue is that Microsoft did not post any documentation about this, hence why people say ānot supportedā. One developer can simply open ci.dll in IDA and the .pdb is available from Microsoft; making reversing / exporting of these functions quite easy.
Once you created your import .libs, they wonāt change. There are many Windows editions released that heavily rely on these functions and Microsoft 100% will not re-invent the wheel and change them.
You can reliably use āundocumentedā functions (up to point), but of course you need to understand what you are doing.
@brad_H said:
@Mecanik said:
I am really not going to comment on stuff here, because there would be too much to say.The least I will say @brad_H is that you are very wrong with many things, especially ObCallbacks and virtualization like VMProtect.
To answer your question:
- You can check for signed binaries in Kernel, Windows does it, always had since VISTA. Look at ci.dll exported function CiCheckSignedFile, it will do everything you want.
- You cannot āsecureā IOCTLās with this, find another method of communication, like shared mapping. Or even simpler, encrypt your data both ways.
To give you a hand, do note that ci.dll has changed a lot until Windows 10 and there is no documentation for this. You have to manually reverse the structs and function parameters, generate the .lib file and link against your driver.
dumpbin /EXPORTS c:\windows\system32\ci.dll lib /def:ci.def /machine:x64 /out:ci.lib
Enjoy.
Doing this using the ci.dll is a very risky way of doing it considering most of it is undocumented and the structures change vastly from time to time, its basically not a possible solution for a product.
Everything is āriskyā, even ādocumentedā functionality. Thatās not the point, and that doesnāt stop you from using something thatās already there.
In this case, ci.dll has not changed that much besides new functions being added; structures seem the same since Win 7 (tested) tp Win 10 (tested).
Spoken like an experienced student, or a researcher. Who writes software used by hundreds of users. Not to be confused with āhundreds of thousandsā or āmillionsā
I donāt have time to write a diatribe on thisā¦. But, the point of something being āsupportedā is that the functionality is documented and the dev owner has agreed they wonāt change the contract inherent in the function. This isnāt Linux where we change the parameters of kernel functions between releases. Even more importantly, when a function is āsupportedā it means you can expect it to properly achieve its documented goal. It acquires the necessary locks. It works at the documented IRQLs. The dependencies of undocumented functions areā¦ undocumented.
This is not to say that you can never use ANY undocumented function. There are, indeed, some functions that have been around āa long timeāā¦ have not changedā¦ are well knownā¦ and provide utility thatās not otherwise available. Itās a matter of risk, as you recognize. What type of software you write, what that software is used for, the environment in which its used, the consequences of failure, and the ultimate users of the software all impact what level of risk is acceptable. If you write some gritty utility that āhundreds of peopleā people can download from GitHubā¦ thatās one level of risk. If you write software thatās run on millions of desktops and servers worldwide, thatās a different level of risk. If your software controls some flying contraption, with or without people on board, thatās yet another level of risk.
We all get to choose, evaluate, and determine the level of risk with which we are comfortable. Thatās called āengineering.ā
Peter
There are literally a dozen functions inside NT that havenāt changed (much) since XP, and people still use them. In fact, is it more often better to use āundocumentedā functions/functionality for several reasons.
I did not say that using any undocumented API is wrongā¦ Itās always a trade-off that you need to think about. If thereās a benefit to using the undocumented API, You have to āevaluate the riskā and decide if itās worth it, as Peter said. Evaluating the risk can be very hard at times and requires YEARS of experience with windows kernel and knowledge about potential issues and edge cases. We just suggested that in this specific case itās not worth it, You can read my previous comments to understand why itās not worth itā¦ In my opinion.
I simply hate Win32 API, they are slow, can be intercepted easily, etc.
1 - the ācan be intercepted easilyā argument is just plain incorrect. Moreover, even if it would be correct, why do you care?
2 - āhate Win32 APIā - well, nobody ālovesā itā¦ but is it a reason to take the risk?
3 - āthey are slowā - Design decisions that are based on āruntime performanceā reasons, should be backed by tests. If you perform a test and
observe a performance overhead that is caused by a Win32 API (And, this issue is solved by switching to a undocumented API) this may be a good
reason to use this undocumented API, after evaluating the risk. Simply rejecting ALL the Win32 API because itās āslowā is not a good reason in my
opinion - this is called āpremature optimizationā.
As for the ci.dll, the only issue is that Microsoft did not post any documentation about this, hence why people say ānot supportedā. One developer can simply open ci.dll in IDA and the .pdb is available from Microsoft; making reversing / exporting of these functions quite easy.
This was already reverse engineered: https://github.com/Ido-Moshe-Github/CiDllDemo
The time spent on reverse engineering these functions is not a considerationā¦ Reverse engineering is something you do once, compare it to supporting millions of customer machines for years and having complicated code in your product.
Once you created your import .libs, they wonāt change. There are many Windows editions released that heavily rely on these functions and Microsoft 100% will not re-invent the wheel and change them.
Why are you so sure about it? MSFT already changed this specific function in the past, so how can you be sure?
Also, itās not only whether āitās going to change or notā - there are caveats to using undocumented APIsā¦ The simplest example is using APC - How are you handling the unload of your driver safely? Are you aware of the synchronization and locking issues?
simplest example is using APC
LOLā¦ that is a GREAT example. There was a client who wanted us to help them with a driverā¦ this was YEARS ago. They had some bugs. It use Kernel APCs all over the place. We politely declined.
Peter
@0xrepnz said:
I did not say that using any undocumented API is wrongā¦ Itās always a trade-off that you need to think about. If thereās a benefit to using the undocumented API, You have to āevaluate the riskā and decide if itās worth it, as Peter said. Evaluating the risk can be very hard at times and requires YEARS of experience with windows kernel and knowledge about potential issues and edge cases. We just suggested that in this specific case itās not worth it, You can read my previous comments to understand why itās not worth itā¦ In my opinion.
OK; we are jumping from one thing to another. Of course you have to evaluate risk, and of course you need years of experience, but it is well worth it for many reasons. The thread asked for signature checking in Kernelā¦ so I have a potential solution. How is this solution taken is up to the OP.
@0xrepnz said:
1 - the ācan be intercepted easilyā argument is just plain incorrect. Moreover, even if it would be correct, why do you care?
2 - āhate Win32 APIā - well, nobody ālovesā itā¦ but is it a reason to take the risk?
3 - āthey are slowā - Design decisions that are based on āruntime performanceā reasons, should be backed by tests. If you perform a test and
observe a performance overhead that is caused by a Win32 API (And, this issue is solved by switching to a undocumented API) this may be a good
reason to use this undocumented API, after evaluating the risk. Simply rejecting ALL the Win32 API because itās āslowā is not a good reason in my
opinion - this is called āpremature optimizationā.
1 - you must be joking? ācan be intercepted easilyā = just put a detour on CreateFile in your current process when you read your license file, LOL.
2 - Yes. Many reasons, too many actually. I`m not going to start listing them, you need to do your own research and see why.
3 - All WinAPIās are slow, tests have been done, and this is a fact. It is much faster to just call Nt* functions directly from ntdll.dll than using for example Kernel32.dll functions. I wonāt go into system calls, which are just amazing in performance and security.
The reality is that Microsoft had to create another layer of functions which are easy to use for newbie developers. I just do not see another reason as these are not cross platform, and they call the same functions from ntdll.dll for decades, and still will.
Example:
HANDLE hFile = CreateFileW(L"banana.txt", GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
Much easier than:
HANDLE hFile;
static WCHAR const String [] = L"banana.txt";
static UNICODE_STRING const UnicodeString = RTL_CONSTANT_STRING (String);
OBJECT_ATTRIBUTES obj{};
InitializeObjectAttributes(&obj, &str, OBJ_CASE_INSENSITIVE, NULL, NULL);
IO_STATUS_BLOCK isb{};
NTSTATUS status = NtCreateFile(&hFile, FILE_GENERIC_WRITE, &obj, &isb, 0, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_WRITE, FILE_OPEN_IF, FILE_RANDOM_ACCESS|FILE_NON_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
Ya dig?
@0xrepnz said:
This was already reverse engineered: https://github.com/Ido-Moshe-Github/CiDllDemo
The time spent on reverse engineering these functions is not a considerationā¦ Reverse engineering is something you do once, compare it to supporting millions of customer > machines for years and having complicated code in your product.
Glad you Googled and started to understand āhiddenā functions used by Microsoft in your Windows for years. However regarding reversing, it is well worth it if you cannot achieve your goal another way? Also, you know that you can create a pattern and find the same function in next releases right?
@0xrepnz said:
Why are you so sure about it? MSFT already changed this specific function in the past, so how can you be sure?
Because I tested? I`m not running my mouth for no reason, I made tests from Win 7 to Win 10. For me it worked completely fine, and I have been only using official images.
@0xrepnz said:
Also, itās not only whether āitās going to change or notā - there are caveats to using undocumented APIsā¦ The simplest example is using APC - How are you handling the unload of your driver safely? Are you aware of the synchronization and locking issues?
OK, APC. Perhaps open IDA and see how the function works before making assumptions? From what I saw you just Googled about this and found a repo about it, so how can you be so sure about APC? Regardless, if it doesnāt fit in your ābucketā, just use it in a different matter? Be creative? I mean.
Anyway, I came here with good intentions to help the OP; I`m not going to argue about whatās wrong and whatās good; I will leave that for someone else
first, RtlGetVersion is documented
https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-rtlgetversion
second, deciding that all win32 APIs are slow is ridiculous. Yes Microsoft has added compatibility shims innumerable, but what would you suggest instead? the C# managed wrapper classes around the win32 APIs?
and then comes judgement. Not just any judgement, but engineering judgement. Can Microsoft change it? If something is implemented as a macro in a header file the answer is, well no - existing binaries would then fail the ABI. If it is implemented as a function call, then is there a possibility of a different implementation?
certificate checking is a relatively young species of technology and at least two generations of internal functions that deal with these crypto algorithms have been obsoleted already. And we are constantly hearing about quantum algorithms that will outmode the current ones completely so my confidence that this part of a stable API surface is low. I strongly suspect that this will change again. I have no problem with the use of OVERLAPPED.Internal as the NTSTATUS as that has been stable for around 25 years and there is real alternative possible
if you are writing test code or learning, sure. if you are writing code that is just for yourself or your own company, sure. if you are writing code that has broader implications, think and make ethical judgements
@MBond2 said:
first, RtlGetVersion is documented
https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-rtlgetversionsecond, deciding that all win32 APIs are slow is ridiculous. Yes Microsoft has added compatibility shims innumerable, but what would you suggest instead? the C# managed wrapper classes around the win32 APIs?
and then comes judgement. Not just any judgement, but engineering judgement. Can Microsoft change it? If something is implemented as a macro in a header file the answer is, well no - existing binaries would then fail the ABI. If it is implemented as a function call, then is there a possibility of a different implementation?
certificate checking is a relatively young species of technology and at least two generations of internal functions that deal with these crypto algorithms have been obsoleted already. And we are constantly hearing about quantum algorithms that will outmode the current ones completely so my confidence that this part of a stable API surface is low. I strongly suspect that this will change again. I have no problem with the use of OVERLAPPED.Internal as the NTSTATUS as that has been stable for around 25 years and there is real alternative possible
if you are writing test code or learning, sure. if you are writing code that is just for yourself or your own company, sure. if you are writing code that has broader implications, think and make ethical judgements
Well, if thatās what you understood from my comment; I`l just shut up and mind my own business.
The reality is that Microsoft had to create another layer of functions which are easy to use for newbie developers.
Do you seriously not know why there are Nt/Zw APIs and separate Win32 APIs? Seriously??
Peter
@āPeter_Viscarola_(OSR)ā said:
The reality is that Microsoft had to create another layer of functions which are easy to use for newbie developers.
Do you seriously not know why there are Nt/Zw APIs and separate Win32 APIs? Seriously??
Peter
Of course I know why, I just get sarcastic when something frustrates me and I donāt agree with it hahaha.
just put a detour on CreateFile in your current process when you read your license file, LOL.
I donāt understand what is the difference between putting a detour on CreateFile or NtCreateFile, they are both easily done
The reality is that Microsoft had to create another layer of functions which are easy to use for newbie developers. I just do not see another reason as these are not cross platform, and they call the same functions from ntdll.dll for decades, and still will.
Well, actually, they were cross platform (Windows 95 and NT)
Because I tested? I`m not running my mouth for no reason, I made tests from Win 7 to Win 10. For me it worked completely fine, and I have been only using official images.
No - the question was - how can you be sure it will not be changed in the future? This cannot simply be assumed.
OK, APC. Perhaps open IDA and see how the function works before making assumptions? From what I saw you just Googled about this and found a repo about it, so how can you be so sure about APC? Regardless, if it doesnāt fit in your ābucketā, just use it in a different matter? Be creative? I mean.
Well, itās funny. I converted the entire APC source code from assembly to C and wrote articles about it, so googling actually returns the articles I wrote.
https://repnz.github.io/posts/apc/user-apc/
https://repnz.github.io/posts/apc/kernel-user-apc-api/
https://repnz.github.io/posts/apc/wow64-user-apc/
Please try to leave this discussion professional and not personalā¦
Anyway, I came here with good intentions to help the OP
I really understand that, but this doesnāt mean you can just say wrong things you know. I will end the discussion here.
@0xrepnz said:
just put a detour on CreateFile in your current process when you read your license file, LOL.
I donāt understand what is the difference between putting a detour on CreateFile or NtCreateFile, they are both easily done
The reality is that Microsoft had to create another layer of functions which are easy to use for newbie developers. I just do not see another reason as these are not cross platform, and they call the same functions from ntdll.dll for decades, and still will.
Well, actually, they were cross platform (Windows 95 and NT)
Because I tested? I`m not running my mouth for no reason, I made tests from Win 7 to Win 10. For me it worked completely fine, and I have been only using official images.
No - the question was - how can you be sure it will not be changed in the future? This cannot simply be assumed.
OK, APC. Perhaps open IDA and see how the function works before making assumptions? From what I saw you just Googled about this and found a repo about it, so how can you be so sure about APC? Regardless, if it doesnāt fit in your ābucketā, just use it in a different matter? Be creative? I mean.
Well, itās funny. I converted the entire APC source code from assembly to C and wrote articles about it, so googling actually returns the articles I wrote.
https://repnz.github.io/posts/apc/user-apc/
https://repnz.github.io/posts/apc/kernel-user-apc-api/
https://repnz.github.io/posts/apc/wow64-user-apc/Please try to leave this discussion professional and not personalā¦
Anyway, I came here with good intentions to help the OP
I really understand that, but this doesnāt mean you can just say wrong things you know. I will end the discussion here.
Nobody is getting āpersonalā here, itās just a discussion. Sorry if you feel offended in any way; forums are created for this purpose.
As nothing useful is going on in this thread, other than some folks amusing themselves, Iām inclined to close it.
So, this would be a good time to make any final commentsā¦
Peter
I guess you can safely close it since nobody said anything in the past 48 hours