lordnoteworthy / al-khaser Goto Github PK
View Code? Open in Web Editor NEWPublic malware techniques used in the wild: Virtual Machine, Emulation, Debuggers, Sandbox detection.
License: GNU General Public License v2.0
Public malware techniques used in the wild: Virtual Machine, Emulation, Debuggers, Sandbox detection.
License: GNU General Public License v2.0
Is there ways to detect if malicious dll injected?
al-khaser/al-khaser/CodeInjection/QueueUserAPC.cpp
Lines 34 to 35 in c1c491d
hThread is initialized with NULL
and have not been reassigned any value, hence program always exit prematurely.
One approach is to manually enumerate the VEH table to see if a debugger has attached itself, although it's a bit tricky because the VEH table pointer is internal to ntdll and it seems the general approach is to AOB-scan the module to find known code that points to that table. This isn't very portable, so I'll have to try to find a better way.
I built commit 350631a and I get TLS thread attach callback as Bad, no debuggers attached
Windows 7 x64 Administator account
here is full log
https://gist.github.com/friuns2/9c5a72935972b291a82e93bff4cd7f70
Under Debug configuration the option "C/C++-Code Generation-Runtime Library" has value /MT (Multi-threaded), whereas should be "Multi-threaded Debug", /MTd. Currently build fails with the linking error
I'd like to overhaul the way we run checks and standardise how we handle errors. Right now we just return true or false, which isn't very useful.
What I propose is the following:
First we replace BOOL return values with an enum of {good, bad, warn, fail}. Good means the check completed successfully and nothing was detected. Bad means the check completed successfully and detected something. Warn means the outcome of the check was inconclusive. Fail means that some prerequisite was not met or an API call failed.
Secondly we add a standardised mechanism for reporting additional information from checks that doesn't mess up the output format. Effectively we offer a printf
equivalent function for output that pushes messages to an std::vector
which we can then print out after the check completes. I'd like to also have these messages tagged with some sort of level so that we can filter them - by default only showing errors (so we can say why a check failed if it failed), but with the ability to specify a debug level on the command line at a later date for increased verbosity.
@LordNoteworthy I'd like your feedback on this before I go ahead and start the work.
Maybe write this checks?
Parallels Software
Virtual Machine
VirtualBox
QEMU BIOS
VMware
Bochs
I think qemu-qa.exe should be added to the "Processes" section
when use runPE and ErasePe together erasePE zeromemory give an error access violation writing location ?
Crashed in serial_number_bios_wmi
since hRes = pclsObj->Get(_T("SerialNumber"), 0, &vtProp, 0, 0);
failed and we got an invalid vtProp here, which is accessed later StrStrI(vtProp.bstrVal, _T("VMWare")) != 0)
A quick fix is to check if hres is S_OK and vtprop.vt is BT_STR if (hRes == S_OK && vtProp.vt == VT_BSTR)
before doing the string comparaison.
We need a better software versioning for the tool. At the moment, it have this scheme: a.xy when xy is incremented when a new malware-trick is added or bugs got fixed.
I suggest to move to something like this: a.b.c:
If we make a major change, we move from version 1.0.0 to 2.0.0 (like an API change/break, huge enhancement in the framework).
If we make a smaller change, we move from 1.0.0 to 1.1.0 (add a new malware-trick).
If we make a minor change, then we go from 1.0.0 to 1.0.1 (we fixed some bugs or refactored some code).
For continuous integration, it would be nice to integrate TravisCI or Appveyor to Github, so we can build and run some tests when somebody make commits/PR. I did a quick search and found out Appveyor to be suitable for our needs, they offer free Windows VM with different VS versions where we can do our builds/tests.
Open to any suggestions.
We can issue an ATA IDENTIFY command to the disk and see if the returned parameters match known ones from VMs.
Hi, i think this https://github.com/LordNoteworthy/al-khaser/blob/master/al-khaser/Anti%20Analysis/process.cpp#L20 should be changed to "idaq.exe"
al-khaser/Anti Analysis/process.cpp --> Line 20
_T("dumpcap.exe"), // Network traffic dump tool
_T("HookExplorer.exe"), // Find various types of runtime hooks
_T("ImportREC.exe"), // Import Reconstructor
_T("PETools.exe"), // PE Tool
_T("LordPE.exe"), // LordPE
**//_T("dumpcap.exe"), // same with line 23**
Error 1 error C1083: Cannot open source file: 'Anti Dump\SizeOfImage.cpp': No such file or directory
Error 2 error C1083: Cannot open include file: '..\Anti Dump\SizeOfImage.h': No such file or directory
The timing attack functions don't seem to actually return any useful success/failure state right now. I know the goal is to outrun maximum execution periods, but it'd be useful to have the tests fail if APIs don't return the expected values.
It looks like when they were originally written into the main function they were done separately so that the check's message could be printed first, but at the same time did not return a true/false state and weren't called with exec_check. I've since modified the way we display check text (see commit bbf020b) so this should no longer be a problem. Of course we can't pass a parameter to exec_check right now but we can fix that.
I think we need to do a couple of things:
I've commited these changes to the timing-attack-overhaul branch for review. See commit f8d1489 for more info.
I've assigned @LordNoteworthy to review the branch before I merge it. Let me know if you have any feedback.
any way detect CE VEH debugger/page exceptions?
"TLS thread attach callback" also seems work for me in reverse logic. It returns Bad for me if nothing attached but if i attach VEH debugger it returns Good for me. Not sure if its related
Call GetModuleFileName
on a bunch of common DLL names, see if they're inside the system directory (call GetSystemDirectory
to get this path), and fail if they aren't. This detects DLL hijacking.
Hi everyone,
I tried your solution in order to create an hidden Qemu/KVM Sandbox. But when i tried your program on Windows 7 64 bits with the al-khaser_x64.exe i never pass the flag "Checking hard disk size using WMI".
So i looked at the code and make my partition up to 90GB and it still not pass.
I reproduced your code with the MSDN and figured out that you use the parameter vtProp.llVal in order to get the size of the disk. But when i do the same llVal send me random values each time I launch the program. Instead I used the parameter bstrVal which give the exact amount of Bytes on the disk.
I also have to mention that with the x86.exe the "Checking hard disk size using WMI" pass everytime.
How did you learn to use the functions in the windows.h file ?
the ACPI checks (vmware_firmware_ACPI, vbox_firmware_ACPI ...) always return true since
DWORD tableSize = enum_system_firmware_tables(static_cast<DWORD>('ACPI'), tableNames, 4096);
API EnumSystemFirmwareTables is not available under winxp
Should i do TLS checks in a while loop or only at application launch?
i tried put TLS checks in a while loop, then something goes wrong it freezes for 4 seconds and returns true
first interation
0 TLS process attach callback (36 ms)
0 TLS thread attach callback (154 ms)
second interation
1 TLS process attach callback (4999843 ms)
0 TLS thread attach callback (435 ms)
When i run AntiDump detection the cURL stop working, if i use any other detection its working.
[*] Erasing PE header from memory
[*] Increasing SizeOfImage in PE Header to: 0x100000
curl_easy_perform() failed: Couldn't connect to server
curl_easy_perform() failed: Couldn't connect to server
curl_easy_perform() failed: Couldn't connect to server
curl_easy_perform() failed: Couldn't connect to server
curl_easy_perform() failed: Couldn't connect to server
curl_easy_perform() failed: Couldn't connect to server
curl_easy_perform() failed: Couldn't connect to server
curl_easy_perform() failed: Couldn't connect to server
curl_easy_perform() failed: Couldn't connect to server
curl_easy_perform() failed: Couldn't connect to server
curl_easy_perform() failed: Couldn't connect to server
curl_easy_perform() failed: Couldn't connect to server
curl_easy_perform() failed: Couldn't connect to server
curl_easy_perform() failed: Couldn't connect to server
curl_easy_perform() failed: Couldn't connect to server
curl_easy_perform() failed: Couldn't connect to server
Hey, looks like you got a typo into the Anti-VM/generic.cpp file.
The PEB offset on a 64b environment is 0x60, not 0x30 as on 32b :)
PR : #92
{ API_IDENTIFIER::API_GetProductInfo,"kernel32.dll","GetGetProductInfo",API_MIN_OS_VERSION::WIN_XP },//APIs.cpp line 10
GetGetProductInfo supposed to be GetProductInfo?
Hello,
coupe of questions I would like to ask:
If so, it cannot work here because uses function that is missing on Windows XP - EnumProcessModulesEx.
What actually it supposed to detect? VM drivers/services of host or guest? There is no description of this function and it behavior is unclear.
I'm asking because this list
const TCHAR* KnownVMServices[KnownServiceCount] = { L"VBoxDrv", L"VBoxNetAdp", L"VBoxNetLwf", L"VBoxUSB", L"VBoxUSBMon", L"VMnetAdapter", L"VMnetBridge", L"VMnetuserif", L"vmusb", L"vmx86" };
first part contain VirtualBox drivers that are host only. They do not present inside VM. Second part of this list is VMware drivers, but it is little bit old and should include at least this one listed here -> https://usuaria.org.ar/sites/default/files/documentos/1245_SYMANTEC_FIREEYE.pdf However even that list is incomplete and if I look on my vmware I see more values to add (vmusbmouse, vmmemctl, vmx_svga). Should I add it, or VMDriverServices work as expected?
Thanks.
I think qemu-ga.exe should be added to the "Processes" section
https://any.run/
Any.Run is an "amas"(automated malware analysis system). qemu-ga.exe is a agent of qemu virt. system.
As we start to expand the project and include specific ways of doing things (e.g. the API class stuff) we could do with some documentation that helps contributors get up to speed on the codebase.
The program don't drop a file contains all results as it should.
When I searched in cuckoo behavioral analysis what is going wrong, I found that the exception below was raise before the process die.
stacktrace: RaiseException+0x3d FreeEnvironmentStringsW-0x373 kernelbase+0xa49d @ 0x7fefdd7a49d al-khaser_x64+0x1b65 @ 0x13fc31b65 al-khaser_x64+0xe1e8 @ 0x13fc3e1e8 BaseThreadInitThunk+0xd CreateThread-0x53 kernel32+0x1652d @ 0x77a8652d RtlUserThreadStart+0x21 strchr-0x3df ntdll+0x2c521 @ 0x77cbc521
exception.instruction_r: 48 81 c4 c8 00 00 00 c3 48 85 f6 74 08 83 3b 00
exception.symbol: RaiseException+0x3d FreeEnvironmentStringsW-0x373 kernelbase+0xa49d
exception.instruction: add rsp, 0xc8
exception.module: KERNELBASE.dll
exception.exception_code: 0xc000008e
exception.offset: 42141
exception.address: 0x7fefdd7a49d
registers.r14: 0
registers.r15: 0
registers.rcx: 2856608
registers.rsi: 0
registers.r10: 0
registers.rbx: 0
registers.rsp: 2883184
registers.r11: 514
registers.r8: 0
registers.r9: 0
registers.rdx: 0
registers.r12: 0
registers.rbp: 0
registers.rdi: 0
registers.rax: 2012718689
registers.r13: 0
VM OS: Windows 7 - 64 bits
VM RAM: 6144Mo
Cuckoo version : 2.0.6
I try running the binary (al-khaser_x64.exe) on 2 differents sandbox, first in local, second on Internet.
Here you can find the report of the second try: https://cuckoo.cert.ee/analysis/870150/summary/
Precompiled 32 bit binary would be nice, just a thought.
Hello, add to the FirmwareACPI function a validation of known virtual machines:
-VMWare:
PBYTE vmwString = (PBYTE)"VMW";
size_t vmwStringLen = 3;
PBYTE vmwareUpperString = (PBYTE)"VMWARE";
size_t vmwareUpperStringLen = 6;
if (find_str_in_data(vmwString, vmwStringLen, table, tableSize) ||
find_str_in_data(vmwareUpperString, vmwareUpperStringLen, table, tableSize)) {
result = TRUE;
}
-QEMU:
PBYTE bxpString = (PBYTE)"BXP";
size_t bxpStringLen = 3;
PBYTE bochsUpperString = (PBYTE)"BOCHS";
size_t bochsUpperStringLen = 5;
if (find_str_in_data(bxpString, bxpStringLen, table, tableSize) ||
find_str_in_data(bochsUpperString, bochsUpperStringLen, table, tableSize)) {
result = TRUE;
}
It can also be useful trick with checking MSR. The value of most of them in the virtual machine is zero,while on the real - no. But this requires a driver, for example, I used the AsIO.sys like this:
void getMSRValue(DWORD reg, DWORD64 *val) {
if (drvHandle == NULL) { return; }
DWORD dwBytes;
if (DeviceIoControl( drvHandle, 0x0a0406458, ®, sizeof(DWORD),
val, sizeof(DWORD64), &dwBytes, NULL) == NULL) {
printf("DeviceIoControl error: %d\n", GetLastError());
}
}
Thanks!
Hello.
File: Anti VM/Generic.cpp, variable LPTSTR buffer = NULL; (326) will be allocated if no one StrStrI(buffer succeeded. Put it in function's global namespace and check nor NULL before return.
TCHAR* ascii_to_wide_str(CHAR* lpMultiByteStr)
{
/* Get the required size */
CONST INT iSizeRequired = MultiByteToWideChar(CP_ACP, 0, lpMultiByteStr, -1, NULL, 0);
TCHAR *lpWideCharStr = (TCHAR*)MALLOC(**iSizeRequired** * sizeof(TCHAR));
/* Do the conversion */
INT iNumChars = MultiByteToWideChar(CP_ACP, 0, lpMultiByteStr, -1, lpWideCharStr, iSizeRequired);
return lpWideCharStr;
}
Hello,
how do you take bugreports, should I give you patches or you fix it on your own, do you need separate issue for each bug or combined issue post?
Thanks.
Right now we always check PhysicalDisk0, which may not be the OS disk and may be part of an array. I'll improve this to detect which drive(s) the C volume is present on and enumerate physical disk size that way., falling back to the old PhysicalDisk0 check if anything goes wrong.
anti cuckoo like this https://github.com/David-Reguera-Garcia-Dreg/anticuckoo
I get always returned true because of this line, even if i don't attach any debuggers, is this a bug?
BOOL ProcessJob()
{
BOOL foundProblem = TRUE;
I was reading XPN's article about a TotalMeltdown exploit and saw that they had updated their code to check which physical addresses were mapped when doing their search for an _EPROCESS
struct, to avoid BSOD. They do this via the RESOURCEMAP
registry key, which has some REG_RESOURCE_LIST
type values. I hadn't come across that registry value type before and it turns out that it's a fairly in-depth struct that describes hardware resources.
This got me thinking - do the physical memory maps change between a host and a VM, and are VM maps generally the same on every box? I can answer the first one: yes. I wrote a tool to dump the address lists and here are the results:
Host box 1 (Win10, 32GB RAM):
[*] Getting physical memory regions from registry
[*] Reading data from Hardware\ResourceMap\System Resources\Physical Memory\.Translated
--> Memory region found: 0000000000001000 - 000000000009d000
--> Memory region found: 00000000cb52d000 - 00000000cb98c000
[*] Reading data from Hardware\ResourceMap\System Resources\Reserved\.Translated
--> Memory region found: 0000000000001000 - 000000000009d000
[*] Reading data from Hardware\ResourceMap\System Resources\Loader Reserved\.Raw
--> Memory region found: 0000000000000000 - 00000000000a0000
--> Memory region found: 00000000cb526000 - 00000000cb52d000
--> Memory region found: 00000000fec00000 - 00000000fec01000
Host box 2 (Win10, 32GB RAM, Hyper-V enabled):
[*] Getting physical memory regions from registry
[*] Reading data from Hardware\ResourceMap\System Resources\Physical Memory\.Translated
--> Memory region found: 0000000000001000 - 000000000009d000
[*] Reading data from Hardware\ResourceMap\System Resources\Reserved\.Translated
--> Memory region found: 0000000000001000 - 000000000009d000
--> Memory region found: 00000000001f5000 - 00000000001fe000
--> Memory region found: 00000000002fe000 - 00000000003fe000
[*] Reading data from Hardware\ResourceMap\System Resources\Loader Reserved\.Raw
--> Memory region found: 0000000000000000 - 00000000000a0000
--> Memory region found: 00000000001f5000 - 00000000001fe000
--> Memory region found: 0000000000293000 - 0000000000297000
--> Memory region found: 0000000000875000 - 000000000095a000
--> Memory region found: 000000000364c000 - 0000000003675000
--> Memory region found: 000000006929d000 - 000000007fa00000
VirtualBox VM on host 1 (Win8.1 x64, 2GB RAM assigned):
[*] Getting physical memory regions from registry
[*] Reading data from Hardware\ResourceMap\System Resources\Physical Memory\.Translated
--> Memory region found: 0000000000001000 - 000000000009f000
[*] Reading data from Hardware\ResourceMap\System Resources\Reserved\.Translated
--> Memory region found: 0000000000001000 - 000000000000e000
[*] Reading data from Hardware\ResourceMap\System Resources\Loader Reserved\.Raw
--> Memory region found: 0000000000000000 - 000000000000e000
--> Memory region found: 00000000000f0000 - 0000000000100000
VirtualBox VM on host 1 (Win8.1 x64, 10GB RAM assigned):
[*] Getting physical memory regions from registry
[*] Reading data from Hardware\ResourceMap\System Resources\Physical Memory\.Translated
--> Memory region found: 0000000000001000 - 000000000009f000
[*] Reading data from Hardware\ResourceMap\System Resources\Reserved\.Translated
--> Memory region found: 0000000000001000 - 000000000000e000
[*] Reading data from Hardware\ResourceMap\System Resources\Loader Reserved\.Raw
--> Memory region found: 0000000000000000 - 000000000000e000
--> Memory region found: 00000000000f0000 - 0000000000130000
Hyper-V VM on host 2 (Win10, dynamic RAM):
[*] Getting physical memory regions from registry
[*] Reading data from Hardware\ResourceMap\System Resources\Physical Memory\.Translated
--> Memory region found: 0000000000001000 - 00000000000a0000
[*] Reading data from Hardware\ResourceMap\System Resources\Reserved\.Translated
--> Memory region found: 0000000000001000 - 00000000000a0000
[*] Reading data from Hardware\ResourceMap\System Resources\Loader Reserved\.Raw
--> Memory region found: 0000000000000000 - 00000000000a0000
--> Memory region found: 000000007eee9000 - 000000007ef1b000
HyperV VM on host 2 (Win10, 2GB RAM assigned):
[*] Getting physical memory regions from registry
[*] Reading data from Hardware\ResourceMap\System Resources\Physical Memory\.Translated
--> Memory region found: 0000000000001000 - 00000000000a0000
[*] Reading data from Hardware\ResourceMap\System Resources\Reserved\.Translated
--> Memory region found: 0000000000001000 - 00000000000a0000
[*] Reading data from Hardware\ResourceMap\System Resources\Loader Reserved\.Raw
--> Memory region found: 0000000000000000 - 00000000000a0000
--> Memory region found: 000000007eee9000 - 000000007ef1b000
There are patterns here that we can probably exploit, although I'd like more data samples to be sure.
A preliminary test would be:
Reserved\.Translated
has anything other than 1 entry, skip test.Loader Reserved\.Raw
has anything other than 2 entries, skip test.Reserved\.Translated
is 0000000000000000 - 000000000000e000
and Loader Reserved\.Raw
contains an entry equal to 0000000000000000 - 000000000000e000
.Reserved\.Translated
is 0000000000001000 - 00000000000a0000
and Loader Reserved\.Raw
contains an entry equal to 0000000000000000 - 00000000000a0000
.I could do with more data points before I write this up, so @LordNoteworthy it'd be great if you could try this on your side with various VM solutions.
Here's the code for the test utility: PhysMemResourceList.c.txt
If you're feeling lazy and don't wanna compile the above you can use my compiled binary (requires VC Runtime 14 x86): PhysMemResourceList.zip
Let me know what results you get :)
port to Qt5
process.obj : error LNK2019: unresolved external symbol "void __cdecl print_results(int,wchar_t *)" (?print_results@@YAXHPA_W@Z) referenced in function "void __cdecl analysis_tools_process(void)" (?analysis_tools_process@@YAXXZ)
what about this files, i think thay are need!
Checking code for modifications in memory, could be added?
Here is article i tried compile code it working for some extent
https://www.codeproject.com/Articles/17636/Dynamic-TEXT-Section-Image-Verification
I've started writing up documentation around the different checks we do. This will all go together in the GitHub wiki for this repo.
In " Anti VM -> Generic.cpp -> serial_number_bios_wmi() "
(StrStrI(vtProp.bstrVal, _T("0")) != 0) || // VBox
I think this condition is not good, cause it use StrStr() and there is only 1 character, "0".
Thank you.
Right now we just look to see if the disk size is under ~80GB for each check, but I think it'd be useful to retrieve disk size using every known method and verify that they all give the same results. This is a similar approach to how rootkit detection works (e.g. read registry using regular API, read registry manually from the hive file, compare results).
I think there is a problem with your RDTSC diff using VMEXIT.
Pafish detects my VM using this trick but not al-khaser.
I think this is due to the missing 500 ms sleep present in the pafish one :
for (i = 0; i < 10; i++) {
avg = avg + rdtsc_diff_vmexit();
Sleep(500);
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.