GithubHelp home page GithubHelp logo

lordnoteworthy / al-khaser Goto Github PK

View Code? Open in Web Editor NEW
5.8K 240.0 1.2K 2.58 MB

Public malware techniques used in the wild: Virtual Machine, Emulation, Debuggers, Sandbox detection.

License: GNU General Public License v2.0

C++ 90.22% C 7.89% Assembly 0.54% VBA 0.14% C# 1.21%
anti-analysis anti-debugging anti-sandbox anti-vm anti-emulation code-injection malware timing-attacks av-bypass sandbox-evasion

al-khaser's People

Contributors

cybergreg05 avatar dvarshavsky avatar fra-sm avatar graysuit avatar gsuberland avatar haimasker avatar hasherezade avatar hfiref0x avatar iamjplant avatar kaganisildak avatar lordnoteworthy avatar mattiwatti avatar mrexodia avatar not-matthias avatar ntddk avatar nxgr avatar packmad avatar rdzhaafar avatar recvfrom avatar sleekz avatar slow-mouse avatar spriteovo avatar stevemk14ebr avatar xmaple555 avatar y-oyama avatar yp3rion 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  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  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  avatar  avatar  avatar

al-khaser's Issues

CE debugger detection via OutputDebugString

Cheat Engine is actually dumb enough to call OutputDebugString with a load of trivially identifiable stuff that we can use to detect that it is debugging something on the box.

๐Ÿ™„

VEH table debugger detection


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.

Runtime Library error in x86/Debug configuration

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

Wider range of check return values

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.

MmMapIoSpace vm detect

Maybe write this checks?

Parallels Software
Virtual Machine
VirtualBox
QEMU BIOS
VMware
Bochs

Qemu-QA

I think qemu-qa.exe should be added to the "Processes" section

check vtProp.vt == VT_BSTR before accessing vtProp.bstrVal

1

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.

Versioning and CI

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:

  • a: major release
  • b: minor release
  • c: build number

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.

ATA IDENTIFY checks

We can issue an ATA IDENTIFY command to the disk and see if the returned parameters match known ones from VMs.

#bug process.cpp line 23 and 28 is same

	_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**

Overhaul timing attack code

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:

  1. Modify the timing attack functions to return a TRUE/FALSE state.
  2. Add a parameterised version of exec_check (probably using templates)
  3. Switch back to using exec_check to call those functions from main.

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?

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

DLL hijacking check with GetModuleFileName

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.

disk_size_wmi acting weird with llVal

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.

Got a Question

How did you learn to use the functions in the windows.h file ?

Should i do TLS checks in a while loop or only at application launch?

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)

Antidump + cURL

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

APIs.cpp GetGetProductInfo?

{ API_IDENTIFIER::API_GetProductInfo,"kernel32.dll","GetGetProductInfo",API_MIN_OS_VERSION::WIN_XP },//APIs.cpp line 10

GetGetProductInfo supposed to be GetProductInfo?

XP support, VMDriverServices

Hello,

coupe of questions I would like to ask:

  1. does this program intended to support Windows XP?

If so, it cannot work here because uses function that is missing on Windows XP - EnumProcessModulesEx.

  1. The purpose of VMDriverServices routine in Services.cpp
    BOOL VMDriverServices()

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.

Qemu-GA

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.

Contribution / development guidelines

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.

Program raise exception in Cuckoo

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/

FirmwareACPI/SMBIOS for Qemu/VMWare

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, &reg, sizeof(DWORD),
					val, sizeof(DWORD64), &dwBytes, NULL) == NULL) { 								 
                       printf("DeviceIoControl error: %d\n", GetLastError()); 	
        }
}

PC:
pc

VBox:
virtualbox

VMWare:
vmware

Thanks!

Memory leak.

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.

#bug ascii_to_wide_str maybe have a malloc issues

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;

}

Bugreport?

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.

Improve disk size IOCTL check

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.

System Resources layout as a potential VM detection vector

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:

  • If Reserved\.Translated has anything other than 1 entry, skip test.
  • If Loader Reserved\.Raw has anything other than 2 entries, skip test.
  • Detect VirtualBox if Reserved\.Translated is 0000000000000000 - 000000000000e000 and Loader Reserved\.Raw contains an entry equal to 0000000000000000 - 000000000000e000.
  • Detect HyperV if 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

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)

Problem in function "serial_number_bios_wmi()".

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.

Disk size reporting inconsistency check

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).

Problem with rdtsc diff using vmexit

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);
}

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.