Giter VIP home page Giter VIP logo

capemon's People

Contributors

almogch avatar avihayst avatar cccs-mog avatar davidt99 avatar doomedraven avatar enzok avatar gee-eng avatar heck-gd avatar kevoreilly avatar kfirstri avatar nblog avatar r0ny123 avatar razvioverflow avatar snemes avatar themythologist avatar yelenderosen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

capemon's Issues

[MSVC][permissive-][std:c++latest] Capemon failed to build with msvc due to error C2362 error2440 on Windows

Hi all,
Capemon failed to build with msvc due to error C2362 error2440 on Windows. Could you please help look at this issue?

Environment:
Windows: windows server 2019
VS: 2019

Repro steps:
1.open VS2019 x64 tools command
2.git clone https://github.com/kevoreilly/capemon F:\gitP\kevoreilly\capemon
3.cd F:\gitP\kevoreilly\capemon
4.mkdir build_amd64 & cd F:\gitP\kevoreilly\capemonl\build_amd64
5.set VSCMD_SKIP_SENDTELEMETRY=1 & "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat" -host_arch=amd64 -arch=amd64 & set CL= /permissive-
6.msbuild /m /p:Platform=x64 /p:Configuration=Release /p:WindowsTargetPlatformVersion=10.0.18362.0 /p:PlatformToolset=v142 capemon.sln /t:Rebuild

Error info:
F:\gitP\kevoreilly\capemon\CAPE\AmsiDumper.cpp(163,13): error C2362: initialization of 'hr' is skipped by 'got
o error' [F:\gitP\kevoreilly\capemon\capemon.vcxproj]
F:\gitP\kevoreilly\capemon\CAPE\Scylla\IATReferenceScan.cpp(425,15): error C2440: 'initializing': cannot conve
rt from 'const char [2]' to 'CHAR *' [F:\gitP\kevoreilly\capemon\capemon.vcxproj]
F:\gitP\kevoreilly\capemon\CAPE\Scylla\IATReferenceScan.cpp(429,11): error C2440: '=': cannot convert from 'co
nst char [5]' to 'CHAR *' [F:\gitP\kevoreilly\capemon\capemon.vcxproj]
F:\gitP\kevoreilly\capemon\CAPE\Scylla\IATReferenceScan.cpp(433,11): error C2440: '=': cannot convert from 'co
nst char [4]' to 'CHAR *' [F:\gitP\kevoreilly\capemon\capemon.vcxproj]
F:\gitP\kevoreilly\capemon\CAPE\Scylla\IATReferenceScan.cpp(437,11): error C2440: '=': cannot convert from 'co
nst char [4]' to 'CHAR *' [F:\gitP\kevoreilly\capemon\capemon.vcxproj]
F:\gitP\kevoreilly\capemon\CAPE\Scylla\IATReferenceScan.cpp(441,11): error C2440: '=': cannot convert from 'co
nst char [5]' to 'CHAR *' [F:\gitP\kevoreilly\capemon\capemon.vcxproj]
F:\gitP\kevoreilly\capemon\CAPE\Scylla\IATReferenceScan.cpp(445,11): error C2440: '=': cannot convert from 'co
nst char [4]' to 'CHAR *' [F:\gitP\kevoreilly\capemon\capemon.vcxproj]

log
build.log

Deadlock with RtlLookupFunctionEntry-based stack unwinding on 64-bit Windows 10

Starting a 64-bit Winword on current Windows 10 under observation by capemon gets stuck very early on. Attaching to the stuck winword.exe shows the following call stack:

ldrinvertedfunctiontable

Apparently, ntdll!RtlInsertInvertedFunctonTable is called and (according to disassembly of the function) exclusively acquires Slim Reader/Writer lock (SRW) ntdll!LdrpInvertedFunctionTableSRWLock. This would make sense as the function is likely to modify import tables.
While holding the lock, it calls ntdll!LdrProtectMrData which, according to my debugging, eventually calls ntdll!NtProtectVirtualMemory, likely to protect access to those tables (again). Since ntdll!NtProtectVirtualMemory is hooked by capemon, this triggers capemon_x64!enter_hook in order to decide whether to enter the capemon hook for that function or not. This decision is, amongst other things. based on whether the hook is itself called from a hook. To determine this, the stack is unwound by calling capemon_x64!our_stackwalk which on x64 is implemented using ntdll!RtlLookupFunctionEntry.
Unfortunately, this function does not appear to be safe for this kind of thing because it also acquires the already exclusively held ntdll!LdrpInvertedFunctionTableSRWLock. This leads to the observed deadlock.

Disabling hooking of ntdll!NtProtectVirtualMemory without involvement of stack unwinding mitigates the issue:

diff --git a/hooking.c b/hooking.c
index 46e6560..d0d566f 100644
--- a/hooking.c
+++ b/hooking.c
@@ -259,6 +260,9 @@ int WINAPI enter_hook(hook_t *h, ULONG_PTR sp, ULONG_PTR ebp_or_rip)
 {
        hook_info_t *hookinfo;

+       if (h->new_func == &New_NtProtectVirtualMemory)
+               return 0;
+
        if (h->fully_emulate)
                return 1;

This, however, leaves a massive blindspot regarding all calls to that function. This also only works because ntdll!NtProtectVirtualMemory appears to be the only hooked function called while ntdll!LdrpInvertedFunctionTableSRWLock is held.

Trying to hook ntdll!RtlInsertInvertedFunctonTable to temporarily disable hooking for all other APIs called from it (again without involving stack-based decisions) have not been successful because the hook does not seem to be called:

diff --git a/hook_special.c b/hook_special.c
index e0ad8ea..a81cbdc 100644
--- a/hook_special.c
+++ b/hook_special.c
@@ -39,6 +39,15 @@ static int bits_sent = 0;
 static int tasksched_sent = 0;
 static int interop_sent = 0;
 
+extern int g_hooking_disabled;
+
+HOOKDEF(VOID, WINAPI, RtlInsertInvertedFunctionTable, __in PVOID ImageBase, __in ULONG SizeOfImage) {
+	g_hooking_disabled = 1;
+	DebugOutput("RtlInsertInvertedFunctionTable called");
+	Old_RtlInsertInvertedFunctionTable(ImageBase, SizeOfImage);
+	g_hooking_disabled = 0;
+}
+
 HOOKDEF_NOTAIL(WINAPI, LdrLoadDll,
 	__in_opt	PWCHAR PathToFile,
 	__in_opt	PULONG Flags,
diff --git a/hooking.c b/hooking.c
index 46e6560..361b250 100644
--- a/hooking.c
+++ b/hooking.c
@@ -42,6 +42,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #define HOOK_RATE_LIMIT 0x100
 #define HOOK_LIMIT 0x10000
 
+int g_hooking_disabled = 0;
 static lookup_t g_hook_info;
 lookup_t g_caller_regions;
 
@@ -259,6 +260,9 @@ int WINAPI enter_hook(hook_t *h, ULONG_PTR sp, ULONG_PTR ebp_or_rip)
 {
 	hook_info_t *hookinfo;
 
+	if (g_hooking_disabled)
+		return 0;
+
 	if (h->fully_emulate)
 		return 1;
 
diff --git a/hooks.c b/hooks.c
index 6613af9..277af9d 100644
--- a/hooks.c
+++ b/hooks.c
@@ -184,6 +186,8 @@ hook_t full_hooks[] = {
 	HOOK_NOTAIL_ALT(kernelbase, MoveFileWithProgressTransactedW, 6),
 	HOOK_NOTAIL_ALT(kernel32, MoveFileWithProgressTransactedW, 6),
 
+	HOOK(ntdll, RtlInsertInvertedFunctionTable),
+
 	// File Hooks
 	HOOK(ntdll, NtQueryAttributesFile),
 	HOOK(ntdll, NtQueryFullAttributesFile),
diff --git a/hooks.h b/hooks.h
index 38203c6..d2d9a74 100644
--- a/hooks.h
+++ b/hooks.h
@@ -22,6 +22,10 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #include "ntapi.h"
 #include <tlhelp32.h>
 
+HOOKDEF(VOID, WINAPI, RtlInsertInvertedFunctionTable,
+	__in PVOID ImageBase, __in ULONG SizeOfImage
+);
+
 //
 // File Hooks
 //

diff --git a/misc.h b/misc.h
index 1d9ac32..2e222d1 100644
--- a/misc.h
+++ b/misc.h
@@ -101,6 +101,10 @@ typedef HRESULT (WINAPI *_ProgIDFromCLSID)(
 	_Out_ LPOLESTR *lplpszProgID
 );
 
+typedef VOID(WINAPI* _RtlInsertInvertedFunctionTable)(
+	_In_ PVOID						  ImageBase,
+	_In_ ULONG						  SizeOfImage);
+
 void resolve_runtime_apis(void);
 
 DWORD parent_process_id(); // By Napalm @ NetCore2K (rohitab.com)

Another idea I had (and found elsewhere: https://microsoft.public.win32.programmer.kernel.narkive.com/qxCAoEXI/using-rtllookupfunctionentry-for-profiling) was to try to acquire the lock from our_stackwalk to see if it was held or free and RtlLookupFunctionEntry would block or not. Unfortunately, the symbol is not exported from ntdll, so I cannot get at its address.

Other projects have run into this problem as well and proposed a number of solutions, e.g.: dotnet/runtime#32286, DynamoRIO/drmemory#1222

The issue seems to be somewhat Windows-10-specific, because the same capemon_x64.dll is able to start up and monitor the same version of 64-bit Winword on a 64-bit Windows 7 without above workarounds. My guess is that import table mechanics, at least regarding memory protections on them, have changed between Windows 7 and Windows 10. I have not analysed the differences in detail though.

Is my understanding of the mechanics at play correct?
Could my attempts at hooking RtlInsertInvertedFunctionTable or inspecting the state of LdrpInvertedFunctionTableSRWLock from our_stackwalk be made to work somehow?
Any ideas what else could be done about this issue?

Thanks!

Hook for RtlDispatchException is not implemented well

In Windows NT, the function RtlDispatchException is responsible for sending the exception to each registered frame, until it finds one that handles the exception. After this function is done, it will not return to the caller, but will pass control directly to the exception handler.

At hook_process.c(1049), there is a construction that attempts to handle exception. The log_flush call that follows up after, is potentially never called.

So, to fix this problem:

  1. Either put the log_flush call before the call to CAPEExceptionDispatcher
  2. or mark the entire New_RtlDispatchException as HOOKDEF_NOTAIL, which will auto-call the original function after the hook is done.

The problem caused by the current state is the following. Let's have a simple program:

static ULONG ExceptionHandler(LPEXCEPTION_POINTERS ExceptionPointers)
{
    PEXCEPTION_RECORD ExceptionRecord = ExceptionPointers->ExceptionRecord;
    PCONTEXT pContext = ExceptionPointers->ContextRecord;

    printf("Exception %08X at %p\n", ExceptionRecord->ExceptionCode, ExceptionRecord->ExceptionAddress);
    printf("Trying to skip the instruction ...\n");

#ifdef _WIN64
    pContext->Rip += GetInstructionLength((unsigned char *)ExceptionRecord->ExceptionAddress, 64);
#else
    pContext->Eip += GetInstructionLength((unsigned char *)ExceptionRecord->ExceptionAddress, 32);
#endif

    return EXCEPTION_EXECUTE_HANDLER;
}

//int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
void _cdecl main()
{
    printf("Hello, World, I am a test program for cuckoo/CAPE.\n\n");
    //printf("Capemon base address: %p\n", GetModuleHandle(_T("capemon_x64.dll")));

    printf("Before __try\n");
    //__debugbreak();

    __try
    {
        printf("Inside __try\n");
        *(char *)0 = 0;
        printf("After exception\n");
    }
    __except(ExceptionHandler(GetExceptionInformation()))
    {
        printf("Inside __except\n");
    }

    printf("After __except\n");

    printf("\nTestprogram exiting ...\n");
    _getch();
}

When 64-bit version executed in CAPE, it only gives the following console output:

Hello, World, I am a test program for cuckoo/CAPE.
 
* (0): Before __try
* (1): Inside __try
* (4): Inside __except
* (5): After __except
 
Testprogram exiting ...

Hooking failure on .net executable

if hooks = full_hooks; are applied on a .net executable , capemon fails to load . .net Error message pops up .
if hooks are changed to hooks = min_hooks; , it works fine
Sample : ba593b4f4a1ab0b96b2a38e851aed89e

windows 7 sp1, .net 4.0 installed

Detonation failure due to VS2022

The sample 5e56a3c4d4c304ee6278df0b32afb62bd0dd01e2a9894ad007f4cc5f873ab5cf (PowerLoader) fails to detonate properly with 64-bit capemon compiled with VS2022 on Windows 7 x64.

The issue appears to be with the WriteProcessMemory hook which is called early in capture of the injected explorer.exe. Even with an 'empty' hook detonation fails.

image

If capemon is compiled with VS2017 the sample detonates fine, as seen below:

image

LdrLoadDll BaseAddress always NULL

I notice that the value of BaseAddress in the LdrLoadDll is always null. Because we call the LOQ_ntstatus to log the api before we call Old_LdrLoadDll. And the ModuleHandle is an out parameter which is set after the function call. I am wondering why the original implementation is designed this way and if it is intentional.

capemon/hook_special.c

Lines 74 to 79 in 9b7258b

if (!wcsncmp(library.Buffer, L"\\??\\", 4) || library.Buffer[1] == L':')
LOQ_ntstatus("system", "HFP", "Flags", Flags, "FileName", library.Buffer,
"BaseAddress", ModuleHandle);
else
LOQ_ntstatus("system", "HoP", "Flags", Flags, "FileName", &library,
"BaseAddress", ModuleHandle);

In addition, I attempted to move the logging to the HOOKDEF_ALT of LdrLoadDll after the function call. It can correctly display the BaseAddress of the loaded DLL. But some of the DLL, which is nonexist dll, will not enter this HOOKDEF_ALT of LdrLoadDll.

Question: what are maldoc detonation issues?

Hi.

Some hooks we are using in the original Cuckoo monitor are commented out with the // maldoc detonation issues message.
Can you please explain what this comment means?

The hooks themselves seem to be same otherwise, but I am not sure what I am risking by enabling them.
We did not notice any issue with these hooks in the original monitor.

Thanks.

When reading configuration, default values should be set before bailing out

The read_config function bails out without setting default values, when the config file doesn't exist at all.

Use case: For simple capemon debugging, where i just run loader_x64.exe load c:\test\capemon_x64_dbg.dll sample.exe when having kernel debugger on.

Problem: Default value of g_config.hook_type is 0, which is HOOK_HOTPATCH_JMP_INDIRECT. In x64, it causes total havoc in the hooked functions.

InjectDllViaIAT failed in Windows 10

https://capesandbox.com/analysis/352187/
This Lockbit sample has both Import Directory and Import Address Table (IAT) empty.

image

loader.exe will use InjectDllViaIAT to inject the capemon.dll into process.

capemon/loader/loader/Loader.c

Lines 1081 to 1089 in 95ed91f

// If IAT zero, set it to section that contains original import table to prevent LdrpSnapIAT failure
if (NtHeader.IAT_DIRECTORY.VirtualAddress == 0)
{
NtHeader.IAT_DIRECTORY.VirtualAddress = ImportsSection.VirtualAddress;
if (ImportsSection.Misc.VirtualSize)
NtHeader.IAT_DIRECTORY.Size = ImportsSection.Misc.VirtualSize;
else
NtHeader.IAT_DIRECTORY.Size = ImportsSection.SizeOfRawData;
}

Because both Import Directory and IAT is 0, NtHeader.IAT_DIRECTORY.VirtualAddress = ImportsSection.VirtualAddress; this line will do nothing and set IAT to 0 again. Now, Only Import Directory will have valid value and IAT set to 0. According to my test results, this is fine in Windows 7, but it fails to load the capemon in Windows 10.

A quick fix is to set IAT to the FirstThunk we created. ( or just disable InjectDllViaIAT )

diff --git a/loader/loader/Loader.c b/loader/loader/Loader.c
index 96478bb..e73f4b5 100644
--- a/loader/loader/Loader.c
+++ b/loader/loader/Loader.c
@@ -1081,11 +1081,17 @@ rebase:
        // If IAT zero, set it to section that contains original import table to prevent LdrpSnapIAT failure
        if (NtHeader.IAT_DIRECTORY.VirtualAddress == 0)
        {
-               NtHeader.IAT_DIRECTORY.VirtualAddress = ImportsSection.VirtualAddress;
-               if (ImportsSection.Misc.VirtualSize)
-                       NtHeader.IAT_DIRECTORY.Size = ImportsSection.Misc.VirtualSize;
-               else
-                       NtHeader.IAT_DIRECTORY.Size = ImportsSection.SizeOfRawData;
+               if (ImportsSection.VirtualAddress == 0) {
+                       NtHeader.IAT_DIRECTORY.VirtualAddress = pImageDescriptor->FirstThunk;
+                       NtHeader.IAT_DIRECTORY.Size = 8;
+               }
+               else {
+                       NtHeader.IAT_DIRECTORY.VirtualAddress = ImportsSection.VirtualAddress;
+                       if (ImportsSection.Misc.VirtualSize)
+                               NtHeader.IAT_DIRECTORY.Size = ImportsSection.Misc.VirtualSize;
+                       else
+                               NtHeader.IAT_DIRECTORY.Size = ImportsSection.SizeOfRawData;
+               }
        }

        // Now set the import table directory entry to point to the new table

I will open a pull request if this fix is ok.

How to compile it properly

Hi,
I am noticing a huge difference between the capemon I compile and the one downloaded from CAPEv2 repo.
Could you please share how you compile the libraries ?
Debug or Release?
I am using both VS2017 and VS2019 and with this release of capemon I keep having the same issue.
Thank you

Capemon failed to build with "fatal error LNK1104: cannot open file 'atls.lib' " with MSVC on Windows arm64ec

Capemon failed to build with "fatal error LNK1104: cannot open file 'atls.lib' " with MSVC on Windows arm64ec. It can reproduce on latest version on capemon branch. Could you please help look at this issue?

Repro steps:

  1. set VSCMD_SKIP_SENDTELEMETRY=1 & "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat" -host_arch=amd64 -arch=arm64
  2. git clone https://github.com/kevoreilly/capemon F:\capemon
  3. cd F:\capemon
  4. Change "x64" to "ARM64EC" in capemon.sln bson.vcxproj capemon.vcxproj files
  5. msbuild /m /p:Platform=ARM64EC /p:Configuration=Release /p:WindowsTargetPlatformVersion=10.0.22618.0 /p:PlatformToolset=v142 capemon.sln /t:Rebuild

Error info:
LINK : fatal error LNK1104: cannot open file 'atls.lib' [F:\capemon\capemon.vcxproj]

Error log:
Capemon_build_LNK1104.log

Some hooks cause Java programs to crash or hang

Current Behavior

.jars and Java based .exes crash unless I use exclude-apis=RtlDispatchException:NtProtectVirtualMemory

image

Steps to Reproduce

To make sure it wasn't an issue specific with the samples that I'm using, I compiled a simple jar file that just prints "hello world"

  1. Submit the helloworld.jar file to CAPE without any options
  2. Observe that it crashes
  3. Submit the helloworld.jar file with option exclude-apis=RtlDispatchException:NtProtectVirtualMemory
  4. Observe that it successfully runs

Individually, I noticed that:

  • RtlDispatchException causes Java to crash
  • NtProtectVirtualMemory causes Java to hang

Context

Question Answer
Git commit (CAPE) 2391d5ad343f5f307dee4c0b053da64d3c1e9452
OS version Ubuntu 20.04 host, Windows 10 64-bit guest
Java version 11.0.11

Capemon Testing Question

I am interested in testing Yara rules that involve the debugging. Is there any specific technique or development path you follow to test the yara debugging rules? Example would be GuLoader.

DsEnumerateDomainTrusts Hook?

Do you think it'd be worth adding in a hook for DsEnumerateDomainTrusts? Specifically that just shows what ServerName and Flags value is passed.

Here's a run for an EXE that collects a bunch of information and then (I think, but haven't verified) POSTs it to a C2 server: https://capesandbox.com/analysis/81358/ . It would have been useful to see that it also calls DsEnumerateDomainTrustsA to collect domain info.

For future reference, what's the criteria for considering when something like this is worth adding in a hook for?

Thank you!

Reference: https://attack.mitre.org/techniques/T1482/

Question : how does capemon behave with new processes and threads?

Hello, sorry for bothering again.
I was wondering if capemon gets initialized from scratch for every process/thread which is forked from the initial one.
I am creating an inner structure for taking track of some info and it seems it gets initialized once the new process is spawned.
Thank you :)

Crash in yara rule matching seemingly due to compiled rule word-size mismatch

Hi,

I'm observing crashes caused by Yara rule matching when analysing program call chains containing both 32 and 64 bit programs on Windows 10. My test case is Microsoft Excel 2013 with a small XLS file containing a macro that does a WMI query. This causes (amongst lots of other things) svchost.exe and wmiprvse.exe processes being spawned which are 64 bit. These I have seen fail in three ways:

  1. Access violation when trying to find the SRW lock using InternalYaraScan:
    image

  2. Hang in RtlLookupFunctionEntry as if the SRW lock could not be found using InternalYaraScan (but didn't crash either):
    image

  3. Access violation in caller_dispatch():
    image

On a hunch I had capemon.dll write/load the compiled rules to/from separate files like so:

diff --git a/CAPE/YaraHarness.c b/CAPE/YaraHarness.c
index 982bc99..c7d2e0b 100644
--- a/CAPE/YaraHarness.c
+++ b/CAPE/YaraHarness.c
@@ -345,7 +345,11 @@ BOOL YaraInit()
                PathRemoveFileSpec(analyzer_path);
        PathRemoveFileSpec(analyzer_path);
        sprintf(yara_dir, "%s\\data\\yara", analyzer_path);
+#ifdef _WIN64
+       sprintf(compiled_rules, "%s\\capemon64.yac", yara_dir);
+#else
        sprintf(compiled_rules, "%s\\capemon.yac", yara_dir);
+#endif

        yr_initialize();

That made these problems go away.
It appears, the initial hooking of the 32 bit excel.exe writes out rules which confuse a 64 bit yara in programs spawned later.
What's peculiar is that the yara docs promise exactly this not to be the case: https://yara.readthedocs.io/en/stable/capi.html#saving-and-retrieving-compiled-rules

What could be the cause for me to see this behaviour?

Thanks!
Michael

Problem in detonation

Hello.
I work in a company that deals with cybersecurity, my colleague and I are also analyzing capemon and we have found some problems in detonation phase with the golang and with edr bypass techniques used by some malware.

Since cape is also used by companies it would be more appropriate not to disclose certain information in public until it is fixed.
@kevoreilly is it possible to contact you privately to discuss how to fix?

Thanks for your attention.

Unable to place hook. Unable to hook.

I have submitted a sample to CAPE community (https://capesandbox.com/analysis/331258/) that at some point during execution performs several GetCommandLineA() calls. I was expecting to see that particular call (or GetCommandLineW()) in the behavioral analysis. However, it is not there.

Inspecting the analysis logs, there is an explicit error about the API call:

2022-11-09 14:04:25,796 [root] WARNING: b'Unable to place hook on GetCommandLineW'
2022-11-09 14:04:25,812 [root] WARNING: b'Unable to hook GetCommandLineW'

image

I will dig into this trying to find out where the issue arises from, but it could happen with other API calls.

Capemon failed to build with fatal error C1047: The object or library file 'F:\gitP\kevoreilly\capemon\\libyara\lib\libyara64.lib' was created by a different version of the compiler than other objects like 'x64\Release\alloc.obj'

We are building Capemon with Visual Studio 2022 17.8.4 on Windows. It failed to build with fatal error C1047: The object or library file 'F:\gitP\kevoreilly\capemon\libyara\lib\libyara64.lib' was created by a different version of the compiler than other objects like 'x64\Release\alloc.obj'; rebuild all objects and libraries with the same compiler. Could you please help to take a look? Thanks in advance!

Steps to reproduce:

  1. Open VS2022 x64 CMD.
  2. git clone https://github.com/kevoreilly/capemon F:\gitP\kevoreilly\capemon
  3. pushd F:\gitP\kevoreilly\capemon
  4. msbuild /m /p:Platform=x64 /p:Configuration=Release /p:WindowsTargetPlatformVersion=10.0.22621.0 /p:PlatformToolset=v143 capemon.sln /t:Rebuild

Actual result:
LINK : fatal error C1047: The object or library file 'F:\gitP\kevoreilly\capemon\libyara\lib\libyara64.lib' was created by a different version of the compiler than other objects like 'x64\Release\alloc.obj'; rebuild all objects and libraries with the same compiler [F:\gitP\kevoreilly\capemon\capemon.vcxproj]
LINK : fatal error LNK1257: code generation failed [F:\gitP\kevoreilly\capemon\capemon.vcxproj]
LINK : fatal error C1047: The object or library file 'F:\gitP\kevoreilly\capemon\libyara\lib\libyara64.lib' was created by a different version of the compiler than other objects like 'x64\Release\alloc.obj'; rebuild all objects and libraries with the same compiler [F:\gitP\kevoreilly\capemon\capemon.vcxproj]
LINK : fatal error LNK1257: code generation failed [F:\gitP\kevoreilly\capemon\capemon.vcxproj]

Attached build log file:
build.log

Dharma Ransomware won't run with hooks enabled

About accounts on capesandbox.com

  • Issues isn't the way to ask for account acctivation. Ping capesandbox in Twitter with your username

This is opensource and you getting free support so be friendly!

  • Free support from doomedraven ended, no whiskey no support. For something he updated the documentation :)

Prerequisites

Please answer the following questions for yourself before submitting an issue.

  • [x ] I am running the latest version
  • [ x] I checked the documentation and found no answer
  • [ x] I checked to make sure that this issue has not already been filed
  • [ x] I'm reporting the issue to the correct repository (for multi-repository projects)
  • [ x] I'm have read all configs with all optional parts

Expected Behavior

Running without concern and encrypt all the files.

Current Behavior

Dos device mode utility crash, if I disable hooks ( zerohooks=1) will run as expected.
SHA256: b23eb66e588b47a73b393c87467b0b2b0431d9d346368efeaa36a76c7877cd27

Yara.h not found

I am importing the actual VS Project but it seems that some dependencies are broken, are you still working on it?
Thank you

Windows 10 and PEB module hiding

We're trying to use CAPEv2 to analyse malware on Windows 10. After we had various types of analyses fail with changing errors on Windows 10 but succeeding on Windows 7, we dug into a simple test case to try and determine the root cause. We used a simple downloadExe.bat which initially employed powershell.exe but eventually only consisted of an echo hi.

By itself it (obviously) runs fine. When run under observation by capemon.dll it reliably ends in a state where a console window is open and shows error message:

Not enough memory resources are available to process this command.

but no hi. This is when started from CAPE via its web frontend in a freshly resumed Windows 10 VM as well as when run from a debug setup with a manually set up analyzer, analysis.conf and various debug and devel tools at hand (particularly Visual Studio Community 2019 and x96dbg). We focused on only the 32-bit cmd.exe and capemon.dll for now.

Digging into this further we determined that this message is a misleading catch-all follow-up error and that the actual cause is a memory access violation exception in cmd.exe. Digging into this showed LdrResolveDelayLoadedAPI returning a Null Pointer for the ShellExecuteExW function which is indeed delay-loaded in cmd.exe. We were not able to determine a cause for this or reproduce it in simpler hand-written test cases involving a small C program using a delay-loaded ShellExecuteExW to run e.g. nodepad.exe.

By pure coincidence when doing a debug build we then found that disabling the call to hide_module_from_peb() in capemon.c makes our test case run successfully.

hide_module_from_peb(hModule);

Further tests revealed that clearing the LDR_MODULE element using memset() after removing it from the various linked lists seems to cause the fallout we're seeing.

capemon/misc.c

Line 799 in 5f9e800

memset(mod, 0, sizeof(LDR_MODULE));

Disabling it makes our small test-case run through or at least further (see below).

Considering the observed behaviour, it would make sense for LdrResolveDelayLoadedAPI to become confused if module bookkeeping became corrupted ever so slightly by the memset(). It seems unlikely though, that the structure became smaller with Windows 10. Rather I'd speculate there to be more references on it which then point to zeroed memory, perhaps as part of an explicit hardening measure.

What do you make of this?
Are you aware of any security measure introduced with Windows 10 that would prevent modification of the PEB and could be disabled?

What might point to a security measure is a peculiar behaviour of Visual Studio we've observed: While Visual Studio is running (even just the startup project/solution selection screen), there seems to be some kind of DLL hosting and/or debugging aid provided by it which tolerates the memset() in capemon.dll and obscures the problem. While it runs, successive analysis runs not only succeed but also seem to share the same, seemingly preloaded capemon.dll even if it's been replaced on disk in the meantime. As soon as Visual Studio is closed, the error behaviour returns. We've not been able to determine what functionality we're dealing with there and any pointer would be welcome.

Also: Disabling the memset() doesn't solve all our problems. Analyses still fail, but increasingly randomly so. What's particularly confounding is that memory access violation exceptions seem to be silently ignored with release as well as debug builds of capemon.dll which greatly hinders debugging. In the case of cmd.exe they lead to above error message (Not enough resources...) but do not terminate the process so we can not get an automatic post-mortem debugger attach e.g. from WinDbg. The same seems to be the case on Windows 7. We've looked but not been able to find a Windows configuration setting for this. Is there any intentional compiler/linker setting or code causing this behaviour we could disable to trigger faulting on all access errors (not explicitly handled) so we can find more of these problems quicker?

[Question] Analyzing Linux Binaries

Hey,

More of a question then an issue, but is it possible to analyze generic Linux Binaries using capemon or CAPEv2 more generally?

I want to analyze some Binaries inside of a docker container. I successfully wrote a machinery module to work with docker and CAPEv2, but I'm quickly realizing now that it looks like (based on capemon code) that it likely only supports Windows APIs.

So, my question is, is it possible with CAPEv2 to analyze generic linux binaries (either in or out of a container) and if not how difficult would it be to add functionality to capemon for this?

BUG: Functions parsing InLoadOrderModuleList have wrong ending condition

  1. The structure LDR_MODULE should be renamed to LDR_DATA_TABLE_ENTRY. This is the name under which the structure is publicky known

  2. These functions, parsing the InLoadOrderModuleList have their ending condition wrong and are touching random data via mod->BaseAddress.

  • add_all_dlls_to_dll_ranges
  • convert_address_to_dll_name_and_offset
  • hide_module_from_peb
  • get_basename_of_module

I'll prepare pull request for this.

Crash due to wrong prototype for NtAllocateVirtualMemoryEx

I've been seeing crashes in the NtAllocateVirtualMemoryEx hook as can be seen here:
virtualallocex-access-violation
(please excuse the German UI, the debug machine was not mine)

It looked like a call-by-value with a large operand to me and pointed me towards the __inout MEM_EXTENDED_PARAMETER Parameters argument to the function. Since I've never seen such a large structure being passed by value in any API I dug a bit and found this alternative usage much more in line with my experience: dotnet/runtime#12779

After changing the prototype to use a pointer like so, the crashes went away:

	__inout  MEM_EXTENDED_PARAMETER *Parameters,

See also: https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc2

This also jives with Parameters being an array of MEM_EXTENDED_PARAMETERs defined by last argument ParameterCount.

Sample seem hangs and not connect to C2

https://capesandbox.com/analysis/193484/

The sample payload is a CobaltStrike stage beacon, wrapped by a loader written in golang. The C2 addr of it is 39.103.191.231,but in the network analysis of the task, there is no host item of the C2.
image

When i try to debug the sample in my local cape sandbox, i set a breakpoint at next instruction of the shellcode call LoadLibraryA(wininet), then i push f9, it will never hit the breakpoint("运行中" means running).
image

Infinite recursion from GetThreadID in Debugger

Hi,

I'm seeing stack overflow exceptions on Windows 10 with even the simplest program doing a single API call:

#include <stdio.h>
#include <Windows.h>

int main()
{
    Sleep(10000);
    DWORD threadid = GetCurrentThreadId();
}

call-stack

Unfortunately, I was not able to grab any meaningful backtrace beyond it happening in enter_hook() and operate_on_backtrace().
Through single stepping the code I think to have found the root cause but can only describe it verbally with links into the capemon source code:

  • enter_hook() calls __called_by_hook() to prevent hook recursion:
    if ((hookinfo->disable_count < 1) && (h->allow_hook_recursion || (!__called_by_hook(sp, ebp_or_rip) /*&& !is_ignored_thread(GetCurrentThreadId())*/))) {
  • __called_by_hook() runs addr_in_our_dll_range() via operate_on_backtrace():
    return operate_on_backtrace(stack_pointer, frame_pointer, NULL, addr_in_our_dll_range);
  • operate_on_backtrace() in the 64 bit version runs our_stackwalk() to retrieve the number of strack frames to look at:
    frames = our_stackwalk(_rip, sp, backtrace, HOOK_BACKTRACE_DEPTH);
  • our_stackwalk() will return zero if the SRW lock is held or an EXCEPTION_EXECUTE_HANDLER exception occurs (I'm fuzzy on the details of the latter):
    if (srw_lock_held())
    __except(EXCEPTION_EXECUTE_HANDLER)
  • this will cause operate_on_backtrace() to never call addr_in_our_dll_range() and will default to returning zero

This in the context of __called_by_hook() means that enter_hook() was not triggered from another hook. This essentially creates potential for unwanted hook recursion whenever the SRW lock is held or that execution exception occurs during stack unwinding.

This seems to quite reliably be triggered and turned into infinite recursion by the Debugger:

  • after the above __called_by_hook() having told enter_hook() that it was not called by a hook, api_dispatch() is called
  • api_dispatch() may (and in my observation basically always does) call InitNewThreadBreakpoints()
  • InitNewThreadBreakpoints() calls CreateThreadBreakpoints()
  • CreateThreadBreakpoints() calls GetThreadId()
  • GetThreadId() internally (at least on Windows 10) calls NtQueryInformationThread() -> which is hooked

This causes instantaneous inifinite hook recursion on any hooked API call (at the very least if the SRW lock is held), leading to the observed stack overflow.

To recap, the call chain is:

/any API call/ -> [recurse: enter_hook() + __called_by_hook() == 0 -> api_dispatch() -> InitNewThreadBreakpoints() -> CreateThreadBreakpoints() ->GetThreadId() -> NtQueryInformationThread()]

My workaround looks like this:

diff --git a/hooking.c b/hooking.c
index 443ae50..d1af8ef 100644
--- a/hooking.c
+++ b/hooking.c
@@ -178,7 +178,14 @@ int addr_in_our_dll_range(void *unused, ULONG_PTR addr)

 static int __called_by_hook(ULONG_PTR stack_pointer, ULONG_PTR frame_pointer)
 {
-       return operate_on_backtrace(stack_pointer, frame_pointer, NULL, addr_in_our_dll_range);
+       int rc = operate_on_backtrace(stack_pointer, frame_pointer, NULL, addr_in_our_dll_range);
+       if (rc < 0) {
+               // be cautious if we couldn't operate on the backtrace at all. This can be
+               // due to SRW lock being held or exceptions when trying to evaluate the backtrace.
+               return 1;
+       }
+
+       return rc;
 }

 int called_by_hook(void)
diff --git a/hooking_64.c b/hooking_64.c
index 153fba5..04d3230 100644
--- a/hooking_64.c
+++ b/hooking_64.c
@@ -1112,7 +1112,7 @@ BOOL srw_lock_held()
        return FALSE;
 }

-static unsigned int our_stackwalk(ULONG_PTR _rip, ULONG_PTR sp, PVOID *backtrace, unsigned int count)
+static int our_stackwalk(ULONG_PTR _rip, ULONG_PTR sp, PVOID *backtrace, unsigned int count)
 {
        /* derived from http://www.nynaeve.net/Code/StackWalk64.cpp */
        __declspec(align(64)) CONTEXT ctx;
@@ -1124,7 +1124,7 @@ static unsigned int our_stackwalk(ULONG_PTR _rip, ULONG_PTR sp, PVOID *backtrace
        unsigned int frame;

        if (srw_lock_held())
-               return 0;
+               return -1;

        __try
        {
@@ -1149,17 +1149,17 @@ static unsigned int our_stackwalk(ULONG_PTR _rip, ULONG_PTR sp, PVOID *backtrace
        }
        __except(EXCEPTION_EXECUTE_HANDLER)
        {
-               return 0;
+               return -1;
        }
 }

 int operate_on_backtrace(ULONG_PTR sp, ULONG_PTR _rip, void *extra, int(*func)(void *, ULONG_PTR))
 {
-       int ret = 0;
+       int ret = -1;
        PVOID backtrace[HOOK_BACKTRACE_DEPTH];
        lasterror_t lasterror;
-       WORD frames;
-       WORD i;
+       int frames;
+       int i;

        get_lasterrors(&lasterror);

What this does is make our_stackwalk() indicate the inability to walk the stack at all by returning -1. This will still make operate_on_backtrace() not call addr_in_our_dll_range() but the changed return code default of -1 will again indicate that fact to the caller. The only caller evaluating the return code at all is __called_by_hook(). There we now cautiously return 1, meaning "yes, we've been or at least could have been called from a hook". This successfully prevents the infinite recursion and subsequent stack overflow in my tests.

Does any of that make sense?

Tabs vs. spaces

Hi, we are moving from our old cuckoo-modified fork to CAPEv2 and I noticed that tabs and spaces are used randomly across the code base. Would you consider fixing this? This would greatly help us with merging our changes (some of which we plan to contribute after the migration) and generally with development later. Should be easy to do with the help of the Visual Studio or some other IDE.

I am willing to do this and create PR. However, I think it would be easier for you to do this on your own then going over the diff in the PR from a stranger. If you want to this and you do not mind a PR, let me know if you would prefer tabs or spaces (we prefer tabs).

Capemon failed to build with "error C2039: 'Dr6': is not a member of '_CONTEXT' " with MSVC on Windows arm64

Capemon failed to build with "error C2039: 'Dr6': is not a member of '_CONTEXT' " with MSVC on Windows arm64. It can reproduce on latest version bfc50b2963d58739f77b907f1465c73880938a80 on capemon branch. Could you please help look at this issue?

Repro steps:

  1. set VSCMD_SKIP_SENDTELEMETRY=1 & "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat" -host_arch=amd64 -arch=arm64
  2. git clone https://github.com/kevoreilly/capemon F:\capemon
  3. cd F:\capemon
  4. Change "x64" to "arm64" in capemon.sln bson.vcxproj capemon.vcxproj files
  5. msbuild /m /p:Platform=arm64 /p:Configuration=Release capemon.sln /t:Rebuild

Error log:

Capemon_msbuild_arm64.log

Error info:

     4>F:\capemon\CAPE\Debugger.c(417,38): error C2039: 'Dr6': is not a member of '_CONTEXT' [F:\capemon\capemon.vcxproj]
       C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\um\winnt.h(6048): message : see declaration of '_CONTEXT' [F:\capemon\capemon.vcxproj]
     4>F:\capemon\CAPE\Debugger.c(448,88): error C2039: 'Dr0': is not a member of '_CONTEXT' [F:\capemon\capemon.vcxproj]
       C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\um\winnt.h(6048): message : see declaration of '_CONTEXT' [F:\capemon\capemon.vcxproj]
     4>F:\capemon\CAPE\Debugger.c(449,145): error C2039: 'Dr0': is not a member of '_CONTEXT' [F:\capemon\capemon.vcxproj]
       C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\um\winnt.h(6048): message : see declaration of '_CONTEXT' [F:\capemon\capemon.vcxproj]
     4>F:\capemon\CAPE\Debugger.c(451,88): error C2039: 'Dr1': is not a member of '_CONTEXT' [F:\capemon\capemon.vcxproj]
       C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\um\winnt.h(6048): message : see declaration of '_CONTEXT' [F:\capemon\capemon.vcxproj]
     4>F:\capemon\CAPE\Debugger.c(452,145): error C2039: 'Dr1': is not a member of '_CONTEXT' [F:\capemon\capemon.vcxproj]
       C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\um\winnt.h(6048): message : see declaration of '_CONTEXT' [F:\capemon\capemon.vcxproj]
     4>F:\capemon\CAPE\Debugger.c(454,88): error C2039: 'Dr2': is not a member of '_CONTEXT' [F:\capemon\capemon.vcxproj]
       C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\um\winnt.h(6048): message : see declaration of '_CONTEXT' [F:\capemon\capemon.vcxproj]
     4>F:\capemon\CAPE\Debugger.c(455,145): error C2039: 'Dr2': is not a member of '_CONTEXT' [F:\capemon\capemon.vcxproj]
       C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\um\winnt.h(6048): message : see declaration of '_CONTEXT' [F:\capemon\capemon.vcxproj]
     4>F:\capemon\CAPE\Debugger.c(457,88): error C2039: 'Dr3': is not a member of '_CONTEXT' [F:\capemon\capemon.vcxproj]
       C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\um\winnt.h(6048): message : see declaration of '_CONTEXT' [F:\capemon\capemon.vcxproj]
     4>F:\capemon\CAPE\Debugger.c(458,145): error C2039: 'Dr3': is not a member of '_CONTEXT' [F:\capemon\capemon.vcxproj]
       C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\um\winnt.h(6048): message : see declaration of '_CONTEXT' [F:\capemon\capemon.vcxproj]
     4>F:\capemon\CAPE\Debugger.c(605,62): error C2039: 'Rip': is not a member of '_CONTEXT' [F:\capemon\capemon.vcxproj]
       C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\um\winnt.h(6048): message : see declaration of '_CONTEXT' [F:\capemon\capemon.vcxproj]
     4>F:\capemon\CAPE\Debugger.c(605,7): error C2198: 'ide': too few arguments for call [F:\capemon\capemon.vcxproj]
     4>F:\capemon\CAPE\Debugger.c(609,57): error C2039: 'Rip': is not a member of '_CONTEXT' [F:\capemon\capemon.vcxproj]
       C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\um\winnt.h(6048): message : see declaration of '_CONTEXT' [F:\capemon\capemon.vcxproj]

Broken sleep hooks resulting in nonstable (not working) TCP sessions

Hello CAPE team!
I'm working on a diploma thesis aimed at analyzing CAPEv2 abilities in tracking Meterpreter based exploits and I have noticed that no matter what my TCP sessions are pretty unstable. That means that after a sucesfull conection all sessions last about 30 secs and then they die off. Presumably because some heartbeat timer expires prematurely.
The culprit seem to be the NtWaitForSingleObject hook which does not react to the force-sleepskip setting. When force-sleepskip=0 option is set, the issue is still there. In order to remove it I had to recompile the monitor with this hook disabled.
Best
Ilzaman

[Compile] LINK : fatal error C1047: The object or library file 'libyara\lib\libyara64.lib' was created by a different version of the compiler

Failed to build after 8bf93ca update the libyara\lib\libyara64.lib and libyara\lib\libyara86.lib file.

Error Info

Build FAILED.
       "T:\t\capemon\capemon.sln" (Rebuild target) (1) ->
       "T:\t\capemon\capemon.vcxproj.metaproj" (Rebuild target) (2) ->
       "T:\t\capemon\capemon.vcxproj" (Rebuild target) (5) ->
       (Link target) ->
         LINK : fatal error C1047: The object or library file 'T:\t\capemon\\libyara\lib\libyara64.lib' was created by a different version of the compiler than other objects like 'x64\Release\alloc.obj'; rebu
       ild all objects and libraries with the same compiler [T:\t\capemon\capemon.vcxproj]
         LINK : fatal error LNK1257: code generation failed [T:\t\capemon\capemon.vcxproj]

    2 Error(s)

Reproduce Command

link.exe /ERRORREPORT:NONE /OUT:"x64\Release\capemon_x64.dll" /INCREMENTAL /ILK:"x64\Release\capemon_x64.ilk" /NOLOGO /LIBPATH:x64\Release /LIBPATH:libyara\lib libyara64.lib bson.lib crypt32.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /DEF:"capemon.def" /MANIFEST /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /manifest:embed /PDB:"x64\Release\capemon_x64.pdb" /SUBSYSTEM:WINDOWS /OPT:REF /OPT:ICF /LTCG:incremental /LTCGOUT:"x64\Release\capemon_x64.iobj" /TLBID:1 /RELEASE /DYNAMICBASE /NXCOMPAT /IMPLIB:"x64\Release\capemon_x64.lib" /MACHINE:X64 /DLL x64\Release\alloc.obj x64\Release\AmsiDumper.obj x64\Release\CAPE.obj x64\Release\Debugger.obj x64\Release\Injection.obj x64\Release\InstrCallback.obj x64\Release\Output.obj x64\Release\ScyllaHarness.obj x64\Release\ApiReader.obj x64\Release\DeviceNameResolver.obj x64\Release\IATReferenceScan.obj x64\Release\IATSearch.obj x64\Release\ImportRebuilder.obj x64\Release\ImportsHandling.obj x64\Release\NativeWinApi.obj x64\Release\PeParser.obj x64\Release\ProcessAccessHelp.obj x64\Release\StringConversion.obj x64\Release\SystemInformation.obj x64\Release\Trace.obj x64\Release\Unpacker.obj x64\Release\w64wow64.obj x64\Release\wow64_fix.obj x64\Release\YaraHarness.obj x64\Release\config.obj x64\Release\capemon.obj x64\Release\decoder.obj x64\Release\distorm.obj x64\Release\instructions.obj x64\Release\insts.obj x64\Release\mnemonics.obj x64\Release\operands.obj x64\Release\prefix.obj x64\Release\textdefs.obj x64\Release\wstring.obj x64\Release\hooking.obj x64\Release\hooking_32.obj x64\Release\hooking_64.obj x64\Release\hooks.obj x64\Release\hook_clr.obj x64\Release\hook_crypto.obj x64\Release\hook_file.obj x64\Release\hook_misc.obj x64\Release\hook_network.obj x64\Release\hook_process.obj x64\Release\hook_reg.obj x64\Release\hook_reg_native.obj x64\Release\hook_services.obj x64\Release\hook_sleep.obj x64\Release\hook_socket.obj x64\Release\hook_special.obj x64\Release\hook_sync.obj x64\Release\hook_thread.obj x64\Release\hook_tls.obj x64\Release\hook_window.obj x64\Release\ignore.obj x64\Release\log.obj x64\Release\lookup.obj x64\Release\misc.obj x64\Release\pipe.obj x64\Release\unhook.obj x64\Release\utf8.obj x64\Release\InstrHook64.obj

Build Command

git clone https://github.com/kevoreilly/capemon.git
cd capemon
REM It can be compiled after restoring libyara lib
REM git checkout 8bf93ca~ libyara\lib\libyara*.lib
msbuild /m /p:Platform=x64 /p:Configuration=Release /p:WindowsTargetPlatformVersion=10.0.22621.0 /p:PlatformToolset=v143 capemon.sln /t:Rebuild

Build Env

  • Commit: capemon(56886e6)
  • VS: 2022 17.7.3
  • System: Microsoft Windows [Version 10.0.22621.2134]

x86 DLL detonation issues in Win10

Currently facing exceptions with a few x86 DLL samples in Win10.
Hash are as followed:
d3095f08ae2d3f9b31dd5696bd593e5de14b4ca665389f0d480ad12318af2682
2cb8f04d41fe34706ff61cba06788faaaca87494721fcf8e86d20b897890a3b1
907b3cc7168067b2e2c4db2318cc9fa2ebc58963571c92665b447c447b6cc3a1
b7e432ebcbff1842f6639e6cc8ba2cca6a7ebe6374d40fda88b9de0fa920b225
f96a79f844cdcd2c31932452a6bf9aac7f04731f8eb72f2e1fa3f00e24d6aa98
2023-05-23 14_59_45-DevVM
2023-05-23 14_45_11-DevVM
2023-05-23 16_07_41-DevVM

Stack seem to get corrupted and as far as I investigated, the problem is not coming from rundll32 itself for broken signature.
Working onto that issue currently but any help would be welcome.

Happy to provide crashdump, memory dumps of the issues.

Execution of dummy x86 dlls give no exceptions.

Improving IsPeImageRaw()

IsPeImageRaw()

The central pointer, where the image is mapped or the raw data is located in memory, is determined. The logic inside IsPeImageRaw() works fine but can fail in many scenarios.

extern "C" int LooksLikeSectionBoundary(DWORD_PTR Buffer)
{
    if (
        (*(DWORD*)((BYTE*)Buffer - 4) == 0) &&           // The end of the previous section has zeros
        (*(DWORD*)((BYTE*)Buffer) != 0)                   // The beginning of the section is non-zero
    )
    {
        // If sectionHeader.VirtualAddress == sectionHeader.SizeOfRawData, the above check would fail
    }
}

For example, in the case of Guloader (7911e39e07995e3afb97ac0e5a4608c10c2e278bef29924ecc3924edfcc495ca), after RtlDecompress, the buffer is mapped into memory. AllocationHandler adds the allocation to the monitor list: AllocationHandler: Adding allocation to tracked region list: 0x00410000, size: 0x5000. Thus, during Free or processExit when the list is processed, a dump is mistakenly taken as a Virtual Section boundary. Specifically, in the case of Guloader, in the first section of the PE file, there is a code buffer placed at the PointerToRawData of the first section (which is strange).

The fix:

I have written a small function that checks the presence of relocations in the buffer containing a valid PE. Based on the validity of the relocations, it determines if the buffer is virtually mapped or raw mapped. This function can be called inside IsPeImageRaw() before the boundary checks as a precedence.

		if (peFile->hasRelocationDirectory() )
		{
			if (CheckRelocsTest((char*)Buffer, peFile) )// Virtual mapped image 
				return 0;
			else	
				return 1;
			
		}
// Test based on validity of relocation table , if mapped images is as per virtual boundary then relocations will be parsed successfully 
extern "C" int CheckRelocsTest(char *pMappedImage, PeParser *peFile)
{
	
	
	PIMAGE_BASE_RELOCATION RelocTable = NULL;
	unsigned int iRelocVaddr = 0;
	
	IMAGE_DOS_HEADER DosHdr = {0};
	IMAGE_FILE_HEADER FileHdr = {0};
	IMAGE_OPTIONAL_HEADER OptHdr = {0};
	PIMAGE_BASE_RELOCATION pRelocEntry = NULL;
	unsigned int RelocBlockSize = 0;
	unsigned int *FixUp = 0;
	
	int i = 0;
	
	if (peFile->hasRelocationDirectory())
	{
	
		pRelocEntry = (PIMAGE_BASE_RELOCATION)((unsigned int)peFile->getCurrentNtHeader()->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + (unsigned int)pMappedImage);
		DebugOutput("CheckRelocs: pRelocEntry->VirtualAddress %d.\n", pRelocEntry->VirtualAddress);

		if (pRelocEntry->VirtualAddress >= peFile->getCurrentNtHeader()->OptionalHeader.SizeOfImage ||  pRelocEntry->VirtualAddress == 0) 
		{
		
			return 0;
		}
		
		while (pRelocEntry->VirtualAddress)
		{
			
			iRelocVaddr = pRelocEntry->VirtualAddress;

			RelocBlockSize = (pRelocEntry->SizeOfBlock - 8) / 2;
			pRelocEntry = (PIMAGE_BASE_RELOCATION) ((unsigned char *)pRelocEntry + 8); // TypeOffset
			
			
			
			while (RelocBlockSize--)
			{
				if (*(unsigned short *)pRelocEntry == 0x3000)
				{
					pRelocEntry = (PIMAGE_BASE_RELOCATION)  ((unsigned char *)pRelocEntry + 2);
					continue;
				}
				
				FixUp = (unsigned int *)(*(unsigned short *)pRelocEntry & 0x0fff);
				DebugOutput("\nFixup value before adding = %x, Page base = %x", FixUp, iRelocVaddr);
				FixUp = (unsigned int *)((unsigned int)FixUp + ((unsigned int)pMappedImage + (unsigned int)iRelocVaddr));

				DebugOutput("\nOriginal Address = 0x%p", *FixUp);

				
				pRelocEntry = (PIMAGE_BASE_RELOCATION)  ((unsigned char *)pRelocEntry + 2);
				
		
			}
			
			if (pRelocEntry >= (PIMAGE_BASE_RELOCATION)peFile->getCurrentNtHeader()->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)
			{
				break;	
			}	

			if (pRelocEntry->VirtualAddress >= peFile->getSectionHeaderBasedFileSize()) 
			
			{
				
				return 0;
			}
		}
		
		
	}
	
	return 1; // Virtual Image
}

Crashed in get_full_keyvalue_pathUS

My sandbox is running at Windows 10.
The crashed happened when NtQueryValueKey hooked function is trigger from PrivateRegQueryValueExT (I guess) in advapi32.dll.

capemon/hook_reg_native.c

Lines 195 to 196 in 64d2130

LOQ_ntstatus("registry", "pok", "KeyHandle", KeyHandle, "ValueName", ValueName,
"FullName", KeyHandle, ValueName);

In loq function, it will handle the "k" : "FullName", KeyHandle, ValueName

capemon/log.c

Line 711 in 64d2130

log_wstring(get_full_keyvalue_pathUS(reg, s, keybuf, allocsize), -1);

Then the PUNICODE_STRING s, which is the ValueName, is passed into get_full_keyvalue_pathUS

capemon/misc.c

Lines 1195 to 1201 in 64d2130

if (in && in->Length) {
unsigned int newlen = get_encoded_unicode_string_len(in->Buffer, in->Length);
wchar_t *incpy = malloc(newlen + (1 * sizeof(wchar_t)));
copy_encoded_unicode_string(incpy, in->Buffer, in->Length, newlen);
ret = get_full_key_pathW(registry, incpy, keybuf, len);
free(incpy);
}

Inside of get_full_keyvalue_pathUS. When accessing buf[i], it crashed because buf is null.

capemon/misc.c

Lines 1153 to 1154 in 64d2130

for (i = 0; i < len / sizeof(wchar_t); i++) {
if (buf[i] == L'\0')

For unknown reason, the ValueName passed to NtQueryValueKey has Length > 0 and Buffer null. That's the root cause of the crash.


Fix is simple, just check in->Buffer before doing anything.

diff --git a/misc.c b/misc.c
index 5bab94a..2df90cb 100644
--- a/misc.c
+++ b/misc.c
@@ -1192,7 +1192,7 @@ wchar_t *get_full_keyvalue_pathW(HKEY registry, const wchar_t *in, PKEY_NAME_INF
 wchar_t *get_full_keyvalue_pathUS(HKEY registry, const PUNICODE_STRING in, PKEY_NAME_INFORMATION keybuf, unsigned int len)
 {
        wchar_t *ret;
-       if (in && in->Length) {
+       if (in && in->Buffer && in->Length) {
                unsigned int newlen = get_encoded_unicode_string_len(in->Buffer, in->Length);
                wchar_t *incpy = malloc(newlen + (1 * sizeof(wchar_t)));
                copy_encoded_unicode_string(incpy, in->Buffer, in->Length, newlen);

Question : Defining new log function for Attribute

Hello, I am trying to extract more information from the API NtCreateUserProcess in particular from the argument AttributeList .
I defined the PPS_ATTRIBUTE_LIST as following, taking the definition from https://github.com/processhacker/processhacker/blob/master/phnt/include/ntpsapi.h

typedef struct _PS_ATTRIBUTE
{
    ULONG_PTR Attribute;
    SIZE_T Size;
    union
    {
        ULONG_PTR Value;
        PVOID ValuePtr;
    };
    PSIZE_T ReturnLength;
} PS_ATTRIBUTE, *PPS_ATTRIBUTE;

typedef struct _PS_ATTRIBUTE_LIST
{
    SIZE_T TotalLength;
    PS_ATTRIBUTE Attributes[1];
} PS_ATTRIBUTE_LIST, *PPS_ATTRIBUTE_LIST;

I am trying to log and print the ULONG_PTR VALUE but all my trials failed. Do you have any suggestion on how to do that?
Cheers

ntdll write protection preventing AppV hooking in Office 2016 32bit

Starting Winword and Excel 2016 32 bit with capemon loaded on recent Windows 10 quickly ends in an error message The operating system is not presently configured to run this application:
error-message
Enabling loader snaps shows that various DLLs can not be found:

DebugString: "0cb8:0cc8 @ 00250593 - LdrGetDllHandleEx - ENTER: DLL name: mso20win32client.dll"
DebugString: "0cb8:0cc8 @ 00250593 - LdrpFindLoadedDllInternal - RETURN: Status: 0xc0000135"
DebugString: "0cb8:0cc8 @ 00250593 - LdrGetDllHandleEx - RETURN: Status: 0xc0000135"
DebugString: "0cb8:0cc8 @ 00250609 - LdrLoadDll - ENTER: DLL name: C:\Program Files (x86)\Common Files\Microsoft Shared\Office16\mso20win32client.dll"
DebugString: "0cb8:0cc8 @ 00250609 - LdrpLoadDllInternal - ENTER: DLL name: C:\Program Files (x86)\Common Files\Microsoft Shared\Office16\mso20win32client.dll"
DebugString: "0cb8:0cc8 @ 00250609 - LdrpResolveDllName - ENTER: DLL name: C:\Program Files (x86)\Common Files\Microsoft Shared\Office16\mso20win32client.dll"
DebugString: "0cb8:0cc8 @ 00250609 - LdrpResolveDllName - RETURN: Status: 0xc0000135"
DebugString: "0cb8:0cc8 @ 00250609 - LdrpProcessWork - ERROR: Unable to load DLL: "C:\Program Files (x86)\Common Files\Microsoft Shared\Office16\mso20win32client.dll", Parent Module: "(null)", Status: 0xc0000135"
DebugString: "0cb8:0cc8 @ 00250609 - LdrpLoadDllInternal - RETURN: Status: 0xc0000135"
DebugString: "0cb8:0cc8 @ 00250609 - LdrLoadDll - RETURN: Status: 0xc0000135"

... and so on for mso30win32client.dll, mso40uiwin32client.dll, mso99Lwin32client.dll and more.

Looking at the supposed location they indeed do not exist there. Instead they live at C:\Program Files (x86)\Microsoft Office\root\VFS\ProgramFilesCommonX86\Microsoft Shared\OFFICE16.

This is confirmed by looking at the loader snaps of an unmonitored Winword.exe in x32dbg which read:

DebugString: "19a8:0580 @ 00954453 - LdrGetDllHandleEx - RETURN: Status: 0xc0000135"
DebugString: "19a8:0580 @ 00954453 - LdrLoadDll - ENTER: DLL name: C:\Program Files (x86)\Common Files\Microsoft Shared\Office16\mso20win32client.dll"
DebugString: "19a8:0580 @ 00954453 - LdrpLoadDllInternal - ENTER: DLL name: C:\Program Files (x86)\Common Files\Microsoft Shared\Office16\mso20win32client.dll"
DebugString: "19a8:0580 @ 00954453 - LdrpResolveDllName - ENTER: DLL name: C:\Program Files (x86)\Common Files\Microsoft Shared\Office16\mso20win32client.dll"
DebugString: "19a8:0580 @ 00954453 - LdrpResolveDllName - RETURN: Status: 0x00000000"
DebugString: "19a8:0580 @ 00954453 - LdrpMinimalMapModule - ENTER: DLL name: C:\Program Files (x86)\Common Files\Microsoft Shared\Office16\mso20win32client.dll"
DLL Loaded: 5AE10000 C:\Program Files (x86)\Microsoft Office\root\VFS\ProgramFilesCommonX86\Microsoft Shared\OFFICE16\Mso20win32client.dll
DebugString: "19a8:0580 @ 00954453 - LdrpMinimalMapModule - RETURN: Status: 0x00000000"

The mechanism behind that apparent redirection is reverse engineered and explained at https://lucasg.github.io/2018/08/22/magic-behind-appvisv/.

Indeed, in the unhooked Winword.exe, disassembly of ntdll exports contain hooks redirecting into module appvisvsubsystems32:
ntopenfile-appv-hook

In the monitored process, they do not. This is likely explained by the following earlier debug output and exceptions:

DebugString: "0cb8:0cc8 @ 00250500 - LdrGetDllHandleEx - ENTER: DLL name: AppVIsvSubsystems32.dll"
DebugString: "0cb8:0cc8 @ 00250500 - LdrpFindLoadedDllInternal - RETURN: Status: 0x00000000"
DebugString: "0cb8:0cc8 @ 00250500 - LdrGetDllHandleEx - RETURN: Status: 0x00000000"
DebugString: "0cb8:0cc8 @ 00250500 - LdrGetDllHandleEx - ENTER: DLL name: AppVIsvSubsystems32.dll"
DebugString: "0cb8:0cc8 @ 00250500 - LdrpFindLoadedDllInternal - RETURN: Status: 0x00000000"
DebugString: "0cb8:0cc8 @ 00250500 - LdrGetDllHandleEx - RETURN: Status: 0x00000000"
DebugString: "0cb8:0cc8 @ 00250515 - LdrpGetProcedureAddress - INFO: Locating procedure "NtOpenKey" by name"
DebugString: "0cb8:0cc8 @ 00250515 - LdrpGetProcedureAddress - INFO: Locating procedure "NtOpenKeyEx" by name"
DebugString: "0cb8:0cc8 @ 00250515 - LdrpGetProcedureAddress - INFO: Locating procedure "NtOpenKeyTransacted" by name"
DebugString: "0cb8:0cc8 @ 00250515 - LdrpGetProcedureAddress - INFO: Locating procedure "NtOpenKeyTransactedEx" by name"
DebugString: "0cb8:0cc8 @ 00250515 - LdrpGetProcedureAddress - INFO: Locating procedure "NtDeleteKey" by name"
DebugString: "0cb8:0cc8 @ 00250515 - LdrpGetProcedureAddress - INFO: Locating procedure "NtFlushKey" by name"
DebugString: "0cb8:0cc8 @ 00250515 - LdrpGetProcedureAddress - INFO: Locating procedure "NtCreateKey" by name"
DebugString: "0cb8:0cc8 @ 00250515 - LdrpGetProcedureAddress - INFO: Locating procedure "NtCreateKeyTransacted" by name"
DebugString: "0cb8:0cc8 @ 00250515 - LdrpGetProcedureAddress - INFO: Locating procedure "NtEnumerateKey" by name"
DebugString: "0cb8:0cc8 @ 00250515 - LdrpGetProcedureAddress - INFO: Locating procedure "NtQueryKey" by name"
DebugString: "0cb8:0cc8 @ 00250515 - LdrpGetProcedureAddress - INFO: Locating procedure "NtQueryObject" by name"
DebugString: "0cb8:0cc8 @ 00250515 - LdrpGetProcedureAddress - INFO: Locating procedure "NtSetInformationKey" by name"
DebugString: "0cb8:0cc8 @ 00250515 - LdrpGetProcedureAddress - INFO: Locating procedure "NtQueryValueKey" by name"
DebugString: "0cb8:0cc8 @ 00250515 - LdrpGetProcedureAddress - INFO: Locating procedure "NtEnumerateValueKey" by name"
DebugString: "0cb8:0cc8 @ 00250515 - LdrpGetProcedureAddress - INFO: Locating procedure "NtSetValueKey" by name"
DebugString: "0cb8:0cc8 @ 00250515 - LdrpGetProcedureAddress - INFO: Locating procedure "NtDeleteValueKey" by name"
DebugString: "0cb8:0cc8 @ 00250515 - LdrpGetProcedureAddress - INFO: Locating procedure "NtRenameKey" by name"
DebugString: "0cb8:0cc8 @ 00250515 - LdrpGetProcedureAddress - INFO: Locating procedure "NtQueryMultipleValueKey" by name"
DebugString: "0cb8:0cc8 @ 00250515 - LdrpGetProcedureAddress - INFO: Locating procedure "NtNotifyChangeKey" by name"
DebugString: "0cb8:0cc8 @ 00250515 - LdrpGetProcedureAddress - INFO: Locating procedure "NtNotifyChangeMultipleKeys" by name"
DebugString: "0cb8:0cc8 @ 00250515 - LdrpGetProcedureAddress - INFO: Locating procedure "NtQuerySecurityObject" by name"
DebugString: "0cb8:0cc8 @ 00250515 - LdrpGetProcedureAddress - INFO: Locating procedure "NtSetSecurityObject" by name"
DebugString: "0cb8:0cc8 @ 00250515 - LdrpGetProcedureAddress - INFO: Locating procedure "NtDuplicateObject" by name"
DebugString: "0cb8:0cc8 @ 00250515 - LdrpGetProcedureAddress - INFO: Locating procedure "NtClose" by name"
EXCEPTION_DEBUG_INFO:
           dwFirstChance: 1
           ExceptionCode: C0000005 (EXCEPTION_ACCESS_VIOLATION)
          ExceptionFlags: 00000000
        ExceptionAddress: 5CCC212B appvisvsubsystems32.5CCC212B
        NumberParameters: 2
ExceptionInformation[00]: 00000001 Write
ExceptionInformation[01]: 776D2AA0 <ntdll.ZwClose> Inaccessible Address
First chance exception on 5CCC212B (C0000005, EXCEPTION_ACCESS_VIOLATION)!
EXCEPTION_DEBUG_INFO:
           dwFirstChance: 1
           ExceptionCode: C0000005 (EXCEPTION_ACCESS_VIOLATION)
          ExceptionFlags: 00000000
        ExceptionAddress: 5CCC2130 appvisvsubsystems32.5CCC2130
        NumberParameters: 2
ExceptionInformation[00]: 00000001 Write
ExceptionInformation[01]: 776D2AA1 ntdll.776D2AA1 Inaccessible Address
First chance exception on 5CCC2130 (C0000005, EXCEPTION_ACCESS_VIOLATION)!
EXCEPTION_DEBUG_INFO:
           dwFirstChance: 1
           ExceptionCode: C0000005 (EXCEPTION_ACCESS_VIOLATION)
          ExceptionFlags: 00000000
        ExceptionAddress: 5CCC212B appvisvsubsystems32.5CCC212B
        NumberParameters: 2
ExceptionInformation[00]: 00000001 Write
ExceptionInformation[01]: 776D2D90 <ntdll.ZwDuplicateObject> Inaccessible Address
First chance exception on 5CCC212B (C0000005, EXCEPTION_ACCESS_VIOLATION)!
EXCEPTION_DEBUG_INFO:
           dwFirstChance: 1
           ExceptionCode: C0000005 (EXCEPTION_ACCESS_VIOLATION)
          ExceptionFlags: 00000000
        ExceptionAddress: 5CCC2130 appvisvsubsystems32.5CCC2130
        NumberParameters: 2
ExceptionInformation[00]: 00000001 Write
ExceptionInformation[01]: 776D2D91 ntdll.776D2D91 Inaccessible Address

This in my interpretation shows how AppVIsvSubsystems32.dll is locating the exports of the functions it wants to hook and then trying to patch them, which is denied.

In a jumping conclusion this lead me to NtProtectVirtualMemory where I had seen an ntdll protection functionality. And indeed, setting ntdll-protect=0 in options of analysis.conf of the CAPEv2 analyzer makes all the above misbehaviour disappear. Disassembly of the ntdll entrypoints shows that AppVIsvSubsystems32.dll is once again able to install its hooks and the loader snaps show the DLLs being loaded successfully from their actual locations. (Word and Excel still don't start up successfully but that seems to be an unrelated problem for another day.)

Should ntdll-protect=0 perhaps become part of the special office settings profile?
Or could/should there be a more general detection of AppV Detour hooking attempts as explained in above article?

(I would suspect that 64bit Office suffers from the same problem but can not easiliy test that because the only workaround for #12 I currently have incidentally consists of disabling the hooking of NtProtectVirtualMemory which also disables ntdll write protection.)

BUGS: get_lasterrors and set_lasterrors

  1. The intrinsic function __readeflags() used in get_lasterrors() returns 64-bit value on 64-bit build. It is necessary to change lasterror_t::Eflags to DWORD_PTR

  2. What is the meaning of the condition at line 372? It causes the problem described below

  3. The code created by conditional __writeeflags() at line 372 in set_lasterrors seems to invoke error in compiler.

How to reproduce the compiler error:

  1. Build capemon in Visual Studio 2019, Platform Toolset 142, Release version X64 (141 builds it just fine).
  2. Set breakpoint to New_NtOpenFile
  3. Run a sample until it stops in New_NtOpenFile:
.text:00000001800A5280                 sub     rsp, 70h
.text:00000001800A5284                 mov     rsi, r9         ; RSI = IoStatusBlock
.text:00000001800A5287                 mov     rbx, r8         ; RBX = ObjectAttributes
.text:00000001800A528A                 mov     ebp, edx        ; EBP = DesiredAccess
.text:00000001800A528C                 mov     rdi, rcx        ; RDI = Pointer to FileHandle
.text:00000001800A528F                 int     3               ; Trap to Debugger (I added this here to stop in debugger)
.text:00000001800A5290                 mov     rcx, r8         ; obj
.text:00000001800A5293                 call    check_for_logging_resumption ; This call doesn't preserve RBX properly
.text:00000001800A5298                 mov     rcx, rbx        ; obj
.text:00000001800A529B                 call    is_protected_objattr ; This call crashes
.text:00000001800A52A0                 test    al, al
.text:00000001800A52A2                 jz      short loc_1800A52AE
.text:00000001800A52A4                 mov     eax, 0C0000022h
.text:00000001800A52A9                 jmp     loc_1800A53B7
  1. Step over the check_for_logging_resumption() function
  2. Notice that RBX is lost during the step oper operation.

I experimented a bit. The V142 platform toolset makes functions get_lasterrors and set_lasterrors inline. As consequence, there are "pushfq - pop" constructs (created by __readeflags() and __writeeflags()) all over the place. This operation causes RSP to be copied into R11 at the beginning of check_for_logging_resumption. RBX is stored to stack cell referenced by R11+imm, but it's restored from different stack cell referenced by RSP+imm.

TLDR: I found that preventing both get_lasterrors and set_lasterrors from being inlined (via void declspec (noinline) get_lasterrors(lasterror_t *errors) will make the bug go away.

CoCreateInstance hook Win64 exclusion

I'm currently fixing up some code in the CoCreateInstance(Ex) hooks where a GUID for Task Scheduler 1.0 objects was missing.

In 01cc21d x64 was excluded from sending pipe commands, apparently due to some issue with maldocs, but I couldn't find any more information about what exactly the problem was.

As it stands, for 64-bit malware that persists itself using a scheduled task and only then becomes active, CAPE doesn't currently track execution of the scheduled task malware process. Do you think anything speaks against at least enabling the TASKSCHED command for all platforms and excluding only WMI, BITS and INTEROP?

If there are no concerns, I'll create a PR with the changes.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.