Giter Site home page Giter Site logo

hfiref0x / tdl Goto Github PK

View Code? Open in Web Editor NEW
1.0K 77.0 330.0 399 KB

Driver loader for bypassing Windows x64 Driver Signature Enforcement

License: BSD 2-Clause "Simplified" License

C 98.80% C++ 0.89% Objective-C 0.31%
dse loader abandonware tdl c driver-loader

tdl's Introduction

TDL (Turla Driver Loader)

Driver loader for bypassing Windows x64 Driver Signature Enforcement

For more info see

System Requirements and limitations

  • x64 Windows 7/8/8.1/10.
  • TDL designed only for x64 Windows, Vista not listed as supported because it is obsolete.
  • Administrative privilege is required.
  • Loaded drivers MUST BE specially designed to run as "driverless".
  • No SEH support for target drivers.
  • No driver unloading.
  • Only ntoskrnl import resolved, everything else is up to you.
  • Dummy driver examples provided.

You use it at your own risk. Some lazy AV may flag this loader as malware.

Differences between DSEFix and TDL

While both DSEFix and TDL uses advantage of driver exploit they completely different on way of it use.

  • DSEFix manipulate kernel variable called g_CiEnabled (Vista/7, ntoskrnl.exe) and/or g_CiOptions (8+. CI.DLL). Main advantage of DSEFix is it simplicity - you turn DSE off - load your driver (or patched one) and nothing else required. Main disadvantage of DSEFix is that on the modern version of Windows (8+) g_CiOptions variable is subject of PatchGuard (KPP) protection, which mean DSEFix is a potential BSOD-generator.
  • TDL does not patch any kernel variables, which makes it friendly to PatchGuard. It uses small shellcode which maps your driver to kernel mode without involving Windows loader (and as result without triggering any parts of DSE) and executes it. This is main advantage of TDL - non invasive bypass of DSE. There are many disadvantages however - the first and main -> your driver MUST BE specially created to run as "driverless" which mean you will be unable to load any driver but only specially designed. Your driver will exist in kernel mode as executable code buffer, it won't be linked to PsLoadedModuleList, there will be other limitations. However this code will work at kernel mode and user mode application will be able communicate with it. You can load multiple drivers, of course if they are not conflict with each other.

How it work

It uses WinNT/Turla VirtualBox kernel mode exploit technique to write code to the kernel memory and after execute this code. TDL uses custom bootstrap shellcode to map your specially designed driver and call it entry point (DriverEntry), note that DriverEntry parameters will be invalid and must not be used. Examples of specially designed drivers available as DummyDrv and DummyDrv2. Your DriverEntry will run at IRQL PASSIVE_LEVEL up to Windows 10 RS1. Starting from Windows 10 RS2 your DriverEntry code runs on IRQL DISPATCH_LEVEL.

Build

TDL comes with full source code. In order to build from source you need Microsoft Visual Studio 2015 U1 and later versions. For driver builds you need Microsoft Windows Driver Kit 8.1 and/or above.

Instructions

  • Select Platform ToolSet first for project in solution you want to build (Project->Properties->General):
    • v120 for Visual Studio 2013;
    • v140 for Visual Studio 2015;
    • v141 for Visual Studio 2017.
  • For v140 and above set Target Platform Version (Project->Properties->General):
    • If v140 then select 8.1 (Note that Windows 8.1 SDK must be installed);
    • If v141 then select 10.0.17763.0 (Note that Windows 10.0.17763 SDK must be installed).

Remove linker option /NOCOFFGRPINFO where it unsupported/unavailable.

Deprecation

TDL based on old Oracle VirtualBox driver which was created in 2008. This driver wasn't designed to be compatible with newest Windows operation system versions and may work incorrectly. Because TDL entirely based on this exact VirtualBox driver version LPE it is not wise to use it on newest version of Windows. Consider this repository as depricated/abandonware. The only possible updates can be related only to TDL loader itself.

Authors

(c) 2016 - 2019 TDL Project

Credits

  • R136a1
  • N. Rin

tdl's People

Contributors

hfiref0x 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

tdl's Issues

No Longer Working

TDL Fails to load the driver on windows 10 OS Build 14393.187.
DebugViewer catches this: EXWORKER: worker exit with system affinity set, worker routine FFFFF80057EAC6A0, parameter FFFFA08FC275B520, item FFFFA08FC275B520
However the driver works just fine if loaded by Win64ast.

These tests were ran using the already build drivers & Furutaka.

BSOD After some ~ 30 Minutes

I have a simple RPM and WPM Driver with Image Notify Routine and when i load it with TDL it works all fine... but after ~ 30 minutes my pc bluescreen. With normal Driver laoder it works without crash

Bluescreen Viewer:
042118-21765-01.dmp 21.04.2018 22:32:51 0x00000109 a39fdee61fd1b590 b3b6eb6c72539df4 0000000000000002 0000000000000018 ntoskrnl.exe ntoskrnl.exe+175930 x64 ntoskrnl.exe+175930 C:\Windows\Minidump\042118-21765-01.dmp 8 15 16299 1.192.684 21.04.2018 22:34:38

Driver device name/Cannot get handle to driver.

This may be a stupid problem (pretty sure im just retarded) but I am having trouble sending requests to my driver.

Usually, when you have your regular driver, after you load it with NtLoadDriver or w/e you would do something like this:

HANDLE hDriver = CreateFileW(
    "\\\\.\\DriverName",
    GENERIC_READ | GENERIC_WRITE,
    FILE_SHARE_READ | FILE_SHARE_WRITE,
    NULL, OPEN_EXISTING, 0, NULL );

And then use the handle with DeviceIoControl to send requests.

However, after loading my driver with TDL CreateFileW always gives me an error. ERROR_FILE_NOT_FOUND: "The system cannot find the file specified.".

I am testing this with the DummyDrv2 code, having only changed the device names.

On DriverEntry I changed the szDrvName to

WCHAR szDrvName[] = L"\\Device\\ResurgenceDrv";

And then on DriverInitialize:

WCHAR szDevName[] = L"\\Device\\ResurgenceDrv";    
WCHAR szSymLink[] = L"\\DosDevices\\ResurgenceDrv";

This is my test code:

int main()
{
    WCHAR szDeviceName[] = L"\\\\.\\ResurgenceDrv";

    HANDLE _hDriver = CreateFileW(
        szDeviceName,
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL, OPEN_EXISTING, 0, NULL
        );
    if(_hDriver == INVALID_HANDLE_VALUE) {
        printf("Failed to get driver handle. Status 0x%X\n", GetLastError());
    } else {
        printf("Acquired a driver handle!\n");
    }
    return EXIT_SUCCESS;
}

I'd appreciate if someone could point out where I am doing something stupid. I am running this on a Win10 x64 VM.

Thanks,
MarkHC

Vmprotect help

hey hfiref0x, awesome job, this is one of the most amazing loaders I have seen

I have a problem, I need to make tdl loader work with vmprotected driver, but it is crashing and as vmprotect do not have symbols, it becomes complicated to see where it is crashing and why(callstack does not give me much information)

Vmprotect is adding to driver IAT hal.dll(HalMakeBeep) dependency, can this be the root of the problem?

How can I get your knowledge? I wanna code/be like you, and can not see much information on the internet, can you link me your favorite books/tutorials?

Will SMEP protection catch this method?

Questions

Hey, i have 2 questions about this TDL.

  1. There is way to "manually" implement SEH to work with driverless drivers ? It is possible to do that? If yes, can u provide some good documentations?
  2. It's possible to bypass PsSetCreateProcessNotifyRoutine (needs /INTEGRITYCHECK)

Regards,
TheAifam5

TDL loaded driver gets unloaded

Hallo, i'm trying to load the dummy-driver with TDL.

(cmd as admin: Furutaka dummy.sys)

The dummy driver gets loaded and prints a debugmessage to windbg.

But when i look after that into driverview or processhacker, the driver isnt loaded.
It seems, that the driver gets unloaded by the system?
I also can't communicate with the driver.

How can i fix this problem?

The System is Windows 10 x64 (1703 - 15063.540).

Thank you for building this awesome Tool!

When creating a "driverless" driver from a new project the entry point should be GsDriverEntry instead of DriverEntry on Windows 10

I was unable to get TDL to load my "driverless" driver when creating my driver from the "Empty WDM Driver" template in VS2015.2 until I started poking around the linker properties of the example projects. I noticed the default value for Configuration Properties -> Linker -> Advanced -> Entry Point is GsDriverEntry, after changing that to DriverEntry or making this change in my code:

NTSTATUS DriverEntry(...) { ... }

to

NTSTATUS GsDriverEntry(...) { ... }

I had no problems getting TDL to load my driver. I suggest mentioning this in the README.md.

OS: Windows 10 Pro x64
Version: 10.0.10586 Build 10586
VS2015 Version: 14.0.25123.00 Update 2
Windows Driver Kit: 10.0.10586.0

Unable to compile project

Hi, i am unable to compile dummydrv2 and i need to compile it "as is" without touching anything.
VS2015, WDK10, Windows 7 x64.

When i try to compile it as it is, (windows 8.1, toolset 141, wkd10) it cannot find ntddk and stuff related to WDK 8.1, when i install WDK81 i cannot even load the project anymore.

Any idea?

Not loading driver on Win10 (1703 - 15063.608)

Attempting to load dummy.sys, seems perfectly fine but the dbgprint appears to have no affect, unsure if the driver has been loaded or not.

A common message that appears when attempting to load:

[7116] windows\core\console\open\src\host\srvinit.cpp(480)\ConhostV2.dll!00007FFC9FEC17FB: (caller: 00007FFC9FED0628) ReturnHr(5) tid(1c50) 80070032 The request is not supported.

Here is the console output:

(c) 2016 - 2017 TDL Project
Supported x64 OS : 7 and above

Ldr: Windows v10.0 build 15063
SCM: Vulnerable driver loaded and opened
Ldr: Kernel base = 0xFFFFF8027E204000
Ldr: Input driver file loaded at 0x00007FF6E05B0000
Ldr: Loading ntoskrnl.exe
Ldr: ntoskrnl.exe loaded at 0x00007FF6892D0000
Ldr: ExAllocatePoolWithTag 0xFFFFF8027E4833A0
Ldr: Shellcode allocated at 0x000002CA929F0000
Ldr: Windows 10 RS2+ bootstrap shellcode selected
Ldr: Resolving kernel import
Ldr: Executing exploit
Ldr: OpenLdr.u.Out.pvImageBase = 0xFFFFDD09E2A62080
Ldr: SUP_IOCTL_LDR_LOAD, success
        Shellcode mapped at 0xFFFFDD09E2A62080, size = 0x00005000
        Driver image mapped at 0xFFFFDD09E2A6238A
Ldr: SUP_IOCTL_SET_VM_FOR_FAST call complete
Ldr: SUP_IOCTL_FAST_DO_NOP
Ldr: SUP_IOCTL_LDR_FREE
SCM: Unloading vulnerable driver
SCM: Vulnerable driver successfully unloaded
SCM: Driver entry removed from registry
Ldr: Driver file removed

After some testing I am able to get the output sometimes. For example, I may have to reboot the computer once or twice and I get an output, next time I get nothing,

IRQL_NOT_LESS_OR_EQUAL and page faults after KB4038782

PsCreateSystemThreadEx seems to be called with IRQL=DISPATCH_LEVEL after the update KB4038782.
It ends up dereferencing nullptr -> page fault at DISPATCH_LEVEL -> IRQL_NOT_LESS_OR_EQUAL.

fffff802`56c9b847 418b06 mov eax,dword ptr [r14]
this is the instruction that causes the issue.
where r14=0000000000000000

Call stack:

nt!KeBugCheckEx
nt!KiBugCheckDispatch+0x69
nt!KiPageFault+0x247
nt!PsCreateSystemThreadEx+0x1df
0xffffba0c`56a00248
0xffffba0c`00000000
0xffffffff`ffff639e
0xffffba0c`56a0039e
nt!KeWaitForSingleObject+0x377
nt!IopSynchronousServiceTail+0x1a0
nt!IopXxxControlFile+0xd9c
nt!NtDeviceIoControlFile+0x56
nt!KiSystemServiceCopyEnd+0x13
0x00007ffa`cb506184

Uninstalling the update is a good solution for now but I'm opening this issue just so you are aware.

shellcode

Maybe it can be simple for you but i really tried and cant figure out, so im trying to rebuild the shellcode, I uncommented the first bootstrap function and call it with null args on main function, then i go in ida and copy all the bytes, and even with no changes it is a bit different of the original shellcode:

4C 89 44 24 18 48 89 54 24 10 48 89 4C 24 08 48 81 EC F8 00 00 00 48 8B 05 43 52 00 00 48 33 C4 48 89 84 24 E0 00 00 00 48 8D 05 D1 FF FF FF 48 05 00 03 00 00 48 89 44 24 50 48 8B 44 24 50 48 89 84 24 98 00 00 00 48 8B 84 24 98 00 00 00 48 63 40 3C 48 8B 4C 24 50 48 8D 44 01 04 48 89 84 24 A0 00 00 00 48 8B 84 24 A0 00 00 00 48 83 C0 14 48 89 44 24 68 48 8B 44 24 68 8B 40 38 89 44 24 4C 8B 44 24 4C 05 00 10 00 00 8B C0 41 B8 54 64 6C 53 8B D0 33 C9 FF 94 24 00 01 00 00 48 05 00 10 00 00 48 89 84 24 80 00 00 00 48 8B 84 24 80 00 00 00 48 25 00 F0 FF FF 48 89 84 24 80 00 00 00 48 8B 44 24 68 83 78 6C 05 0F 86 D7 01 00 00 B8 08 00 00 00 48 6B C0 05 48 8B 4C 24 68 83 7C 01 70 00 0F 84 BE 01 00 00 B8 08 00 00 00 48 6B C0 05 48 8B 4C 24 68 8B 44 01 70 48 8B 4C 24 50 48 03 C8 48 8B C1 48 89 44 24 40 B8 08 00 00 00 48 6B C0 05 48 8B 4C 24 68 8B 44 01 74 89 84 24 88 00 00 00 48 8B 44 24 68 48 8B 40 18 48 8B 8C 24 80 00 00 00 48 2B C8 48 8B C1 48 89 84 24 90 00 00 00 C7 44 24 58 00 00 00 00 8B 84 24 88 00 00 00 39 44 24 58 0F 83 4B 01 00 00 C7 44 24 48 08 00 00 00 8B 44 24 48 48 8B 4C 24 40 48 03 C8 48 8B C1 48 89 44 24 60 48 8B 44 24 40 8B 40 04 39 44 24 48 0F 83 EC 00 00 00 48 8B 44 24 60 0F B7 00 C1 F8 0C 89 44 24 70 83 7C 24 70 03 74 0C 83 7C 24 70 0A 74 5A E9 AB 00 00 00 48 8B 44 24 40 8B 00 48 8B 4C 24 50 48 03 C8 48 8B C1 48 8B 4C 24 60 0F B7 09 81 E1 FF 0F 00 00 48 63 C9 8B 04 08 03 84 24 90 00 00 00 48 8B 4C 24 60 0F B7 09 81 E1 FF 0F 00 00 48 63 C9 48 8B 54 24 40 8B 12 4C 8B 44 24 50 4C 03 C2 49 8B D0 89 04 0A EB 56 48 8B 44 24 40 8B 00 48 8B 4C 24 50 48 03 C8 48 8B C1 48 8B 4C 24 60 0F B7 09 81 E1 FF 0F 00 00 48 63 C9 48 8B 04 08 48 03 84 24 90 00 00 00 48 8B 4C 24 60 0F B7 09 81 E1 FF 0F 00 00 48 63 C9 48 8B 54 24 40 8B 12 4C 8B 44 24 50 4C 03 C2 49 8B D0 48 89 04 0A 48 8B 44 24 60 48 83 C0 02 48 89 44 24 60 8B 44 24 48 48 83 C0 02 89 44 24 48 E9 02 FF FF FF 48 8B 44 24 40 8B 40 04 8B 4C 24 58 03 C8 8B C1 89 44 24 58 48 8B 44 24 40 8B 40 04 48 8B 4C 24 40 48 03 C8 48 8B C1 48 89 44 24 40 E9 A4 FE FF FF 8B 44 24 4C C1 E8 03 89 44 24 4C 48 C7 44 24 78 00 00 00 00 EB 0D 48 8B 44 24 78 48 FF C0 48 89 44 24 78 8B 44 24 4C 48 39 44 24 78 73 21 48 8B 84 24 80 00 00 00 48 8B 4C 24 78 48 8B 54 24 50 4C 8B 44 24 78 4A 8B 14 C2 48 89 14 C8 EB C7 48 C7 84 24 A8 00 00 00 00 00 00 00 C7 84 24 B0 00 00 00 30 00 00 00 48 C7 84 24 B8 00 00 00 00 00 00 00 C7 84 24 C8 00 00 00 00 02 00 00 48 C7 84 24 C0 00 00 00 00 00 00 00 48 C7 84 24 D0 00 00 00 00 00 00 00 48 C7 84 24 D8 00 00 00 00 00 00 00 48 8B 44 24 68 8B 40 10 48 8B 8C 24 80 00 00 00 48 03 C8 48 8B C1 48 C7 44 24 30 00 00 00 00 48 89 44 24 28 48 C7 44 24 20 00 00 00 00 45 33 C9 4C 8D 84 24 B0 00 00 00 BA FF FF 1F 00 48 8D 8C 24 A8 00 00 00 FF 94 24 08 01 00 00 85 C0 7C 0F 48 8B 8C 24 A8 00 00 00 FF 94 24 10 01 00 00 48 8B 8C 24 E0 00 00 00 48 33 CC E8 98 15 00 00 48 81 C4 F8 00 00 00 C3

if i try to use this i get bsod...
yes im using it as a shellcode in C array

i know this can be simple but really want to rebuild to shellcode even with no changes

KMODE_EXCEPTION_NOT_HANDLED Windows 10

Using the Dummy2 Driver Source code included within the solution, I added a couple functions taken from Black Bone Driver (COPY_MEM and ProtectMem) It seems like Copy Mem works fine, but whenever I call for ProtectMem I encounter a BSOD "KMODE_EXCEPTION_NOT_HANDLED".

This works fine if I load it through DSEFix on my other driver code (which is a full fledged driver).

I have attached the source with this ticket, wondering if you could help me identify what could be causing this?
DummyDrv2.zip

IOCTL Communication

IOCTL Apparently isn't compatible with the drivers that can be loaded with TDL? Tried with simple examples, and defined the DriverDispatch in similar way as DriverEntry was defined, no results. However, if someone knows a way, please do respond.

Failed windows 10 pro x64

Turla Driver Loader v1.1.4 started
(c) 2016 - 2019 TDL Project
Supported x64 OS : 7 and above

Ldr: Windows v10.0 build 17763
SCM: Vulnerable driver load failure

I did everything right and I get this, I have already checked all the driver and have no running to lock it.

furutaka x86

hey hfiref0x, I made some changes to furutaka to make it work compiled as x86(wow64)

I changed TDLMapDriver and it's working as expected, fixed some data structures, imports resolving, kernel base address getter, by using heavens gate tecnique

but TDLExploit fails, I am getting DeviceIoControl "Ldr: SUP_IOCTL_LDR_LOAD call failed" and GetLastError 0x32(ERROR_NOT_SUPPORTED) I am reversing virtualBox driver, and there is only one reference to IoIs32bitProcess it looks like it is not blocking anything, can you help me to make furutaka work compiled as x86?

BSOD @ Ldr: Resolving kernel import

Hi,

I updated the DriverEntry and created DriverInitialize to match the Dummy.sys file, however whenever I use the loader to load my driver I end up blue screening at "Ldr: Resolving kernel import". Do you have any tips on checking what may be the cause for this blue screen?

Thanks!

Failed to load vulnerable driver

Turla Driver Loader v1.0.0 started
(c) 2016 TDL Project
Supported x64 OS : 7 and above

Ldr: Windows v10.0 build 10586
SCM: Vulnerable driver load failure

DebugView doesn't show anything. I've also tried using DSEFix, and that also fails to load.

Cannot get handle to driver from user-mode program

Summary

For both my own driver and the dummy driver 2, the driver handle returned from CreateFile in the user-mode program is 0xffffffff. The driver is supposedly loaded without issues. This very same setup worked perfectly on my VMWare Virtual Machine, but it never worked on my actual computer.

Technical specifications

Windows 10 Pro, x64, Version 1703 (OS Build 15063.138)
No Anti-Virus Software installed (Win Defender disabled)
Windows Firewall enabled
No other drivers loaded with TDL

Full details

I used your pre-compiled dummy2.sys driver and loaded it in my system. Everything went very smooth as you can see in the Debug View:

Then I used your code snippet for communicating with the driver, r3request.c and created my user-mode program to test it. However, both in x86 and x64 mode, the handle returned from CreateFile is 0xffffffff.

The last error code shows 2, which means:

ERROR_FILE_NOT_FOUND
2 (0x2)
The system cannot find the file specified.

Feel free to ask anything further, I'll do everything I can to assist you.
Cheers!

Error with LdrLoadDll

C:\Users\hsac1\OneDrive\Desktop\TestKernel1\bin>TDL.exe Test.sys
Turla Driver Loader v1.1.4 started
(c) 2016 - 2019 TDL Project
Supported x64 OS : 7 and above

Ldr: Windows v10.0 build 14393
SCM: Vulnerable driver loaded and opened
Ldr: Kernel base = 0xFFFFF801BB292000
Ldr: Error while loading input driver file
SCM: Unloading vulnerable driver
SCM: Vulnerable driver successfully unloaded
SCM: Driver entry removed from registry
Ldr: Driver file removed

NTSTATUS = 0xC0000428

I could load the dummy.sys, but when I compiled own kernel and tried to load, always error raised.

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.