fancycode / memorymodule Goto Github PK
View Code? Open in Web Editor NEWLibrary to load a DLL from memory.
Home Page: http://www.joachim-bauch.de/tutorials/loading-a-dll-from-memory/
License: Mozilla Public License 2.0
Library to load a DLL from memory.
Home Page: http://www.joachim-bauch.de/tutorials/loading-a-dll-from-memory/
License: Mozilla Public License 2.0
This loader does not support __declspec(thread) variables at all.
Any attempt to access those variables will lead to a crash or memory corruption.
The reason is, that the loader does NOT initialize the implicit tls index (not to be confused with the conventional manual one) at all.
Please read http://www.nynaeve.net/?p=185 for a background on this.
Thanks for your attention.
I don't know if it is py2exe specific issue or upstream(MemoryModule) issue so I create an issue here as well.
I found that py2exe cannot load any UPX compressed pyd modules and returns ERROR_DLL_INIT_FAILED (I have python runtime UPX compressed and embed into exe)
forget to mention, the issue happens when bundle_files = 1. (So the pyd DLL and python runtime DLL are both loaded from memory, and pyd DLL depends on python runtime DLL)
With bundle_files = 2, the problem does not exist.
Will this work with 64 bit dll's.
Basically i am trying to load a 64 bit dll from a 32 bit application.
in MemoryLoadLibraryEx:
successfull = (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, 0);
will raise exception.
it's caused by below lines in MFC file appinit.cpp of function 'void CWinApp::SetCurrentHandles()':
TCHAR szBuff[_MAX_PATH];
VERIFY(::GetModuleFileName(m_hInstance, szBuff, _MAX_PATH)); --> return false
LPTSTR lpszExt = _tcsrchr(szBuff, '.');
ASSERT(lpszExt != NULL);
ASSERT(*lpszExt == '.');
*lpszExt = 0; // no suffix ---> lpszExt will be a null pointer
it seems that the 'code' variables in
successfull = (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, 0);
is not a valid HMODULE or HINSTANCE value.
any one can give me some advices? thanks!
Edit: Posted original question in the wrong repository of the wrong project. Sorry.
Dear,
Does MemoryModule only work on Windows? if yes, How to work on Linux? Can you recommend a good idea? Thanks in advenced!
For some reason, the BuildImportTable function fails on localized versions of Windows. This has been reported to fail on both Swedish and Italian versions.
Line #280 of memorymodule.c evaluates to true.
if (*funcRef == 0) {
result = 0;
break;
}
Perhaps GetProcAddress functions differently on localized versions?
Got problem again in windows 10 updated. Here is the code
typedef LONG(NTAPI *tNtProtectVirtualMemory)(
IN HANDLE ProcessHandle,
IN OUT PVOID *BaseAddress,
IN OUT PULONG NumberOfBytesToProtect,
IN ULONG NewAccessProtection,
OUT PULONG OldAccessProtection);
tNtProtectVirtualMemory pNtProtectVirtualMemory;
void LoadFromMemory(void)
{
void *data;
size_t size;
HMEMORYMODULE handle;
addNumberProc addNumber;
HMEMORYRSRC resourceInfo;
DWORD resourceSize;
LPVOID resourceData;
TCHAR buffer[100];
data = ReadLibrary(&size);
if (data == NULL)
{
return;
}
handle = MemoryLoadLibrary(data, size);
if (handle == NULL)
{
_tprintf(_T("Can't load library from memory.\n"));
goto exit;
}
pNtProtectVirtualMemory = (tNtProtectVirtualMemory)MemoryGetProcAddress(handle, "NtProtectVirtualMemory");
PVOID pAddr = (PVOID)GetModuleHandleA("Test.exe");
ULONG pSize = (ULONG)4;
DWORD Old;
//pNtProtectVirtualMemory(GetCurrentProcess(), &pAddr, &pSize, PAGE_EXECUTE_READWRITE, &Old); //Crashed
_tprintf(_T("From memory: %X\n"), pNtProtectVirtualMemory);
resourceInfo = MemoryFindResource(handle, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION);
_tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo);
resourceSize = MemorySizeofResource(handle, resourceInfo);
resourceData = MemoryLoadResource(handle, resourceInfo);
_tprintf(_T("Memory resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData);
MemoryLoadString(handle, 1, buffer, sizeof(buffer));
_tprintf(_T("String1: %s\n"), buffer);
MemoryLoadString(handle, 20, buffer, sizeof(buffer));
_tprintf(_T("String2: %s\n"), buffer);
//MemoryFreeLibrary(handle);
exit:
Sleep(0);
//free(data);
}
Its load successfully, but when i use
PVOID pAddr = (PVOID)GetModuleHandleA("Test.exe");
ULONG pSize = (ULONG)4;
DWORD Old;
pNtProtectVirtualMemory(GetCurrentProcess(), &pAddr, &pSize, PAGE_EXECUTE_READWRITE, &Old);
it's crashed. then i check is pNtProtectVirtualMemory address correct, here the result.
SS1 : http://prnt.sc/cmfgbk
SS2 : http://prnt.sc/cmfgeh
The relocation address wrong. it pointed to the null.
SetLastError(ERROR_OUTOFMEMORY);
VirtualFree(code, 0, MEM_RELEASE);
should be
VirtualFree(code, 0, MEM_RELEASE);
SetLastError(ERROR_OUTOFMEMORY);
I guess. Otherwise VirtualFree will overwrite LastError code
When Loading a C# DLL the call to
the first PEDecoder::CheckNTHeaders in
PEDecoder::CheckFormat in
_CorDllMain(mscoreei.dll)
fails.
I think its one of the calls to PEDecoder::CheckSection. So something is not wrong with the sections?
Also
if (alignedImageSize != ALIGN_VALUE_UP(lastSectionEnd, sysInfo.dwPageSize))
fails because actually old_header->OptionalHeader.SectionAlignment is used for that. I Think atleast. SectionAlignment is 0x2000 and mscoree.dll checked that with a hardcoded 0x2000.
For ref:
https://github.com/dotnet/coreclr/blob/master/src/utilcode/pedecoder.cpp
I'm not an expert in all this PE stuff so I don't claim to be right
I noticed an issue with TLS callbacks when I was testing ExecuteTLS(). As far as I understood the callback addresses are hardcoded relying on the fact base image address is 0x400000 (at least all the callback pointers in the sample binaries were 0x40xxxx). Thus if base address differs, they become invalid.
But base address seems to change almost always because $400000 location is frequently occupied by the module of the executable itself! So all the modules it loads later occupy completely different addresses. Thus the base address of our memorymodule could have any value and the assumption that it always >= OptionalHeader.ImageBase
becomes incorrect.
AFAIU, to fix the issue these changes must be done:
locationdelta
type to signed as VirtualAlloc(nil, ...)
is likely to return the pointer < $400000ImageBase
value (I'd recommend just not replacing the value of module.headers.OptionalHeader.ImageBase
and using module.codeBase
instead in FinalizeSection
)ExecuteTLS
adjust all pointers (pointer to 1st callback and the callbacks themselves) as following:ptr_reloc = ptr - ImageBase_old + ImageBase_new
Unfortunately I can't provide a patch because I'm developing Delphi translation of your code but I performed these changes and all callback addresses have been determined correctly. For experiments I used this article (I actually have no idea how to create TLS callback so used sample binaries from there). Testing on TLS_Example_1.exe all five callback adresses were equal to the article ones and corrected callback pointers were pointing to memory blocks corresponding the code from the article (55 8BEC 6A 00, etc)
Hello,
Thank you for sharing this great library!
To give a background of my question: I have a program which packages (as data) several extensions (extensions). These extensions will be loaded from memory using your library.
Problem is that those extensions depend on the DLL of my program (which is now part of the executable itself) and other DLLs that were bundled in the same package.
Now, I would like to replace LoadLibrary
and GetProcAddress
with my own versions, which will scan the package and load the bundled DLL or delegate to the original LoadLibrary and GetProcAddress if the DLL is not my program one or one bundled in the package.
Was thinking perhaps an alternate LoadLibrary and GetProcAddress functions can be provided to MemoryLoadLibrary and use those or fall back to system ones.
What you do think? sounds crazy?
Once again, thank you for creating and releasing this library.
I don't really know if this is possible, but loading DLLs and then an EXE that depends on those libraries, and running it, would be a nice feature.
Since i update to this version, it cant load kernel32.dll that with previous version is work.
It's working well with single dll. But if "b.dll" depends on "a.dll", “a.dll” is load from memory, it throws an error. How to solve it?
Thank you forkindly reply.
Can It use for COM such as DirectX11? I got Exception : Unhandled exception at 0x000007FEFD44A06D (KernelBase.dll)
When throwing and catching an exception inside the "memory-loaded" dll the application crashes with "Unhandled exception at ...". Even though the appropriate catch is in place.
This is when using Visual Studio 2010. I've created a repository that demonstrates this problem. Hopefully i am the one who has missed something and the memory loading is working as intended.
Link to repo: https://github.com/Niblitlvl50/DLL-crash-when-loading-dll-into-memory
Thank you.
The binary search in _MemorySearchResourceEntry will loop forever if start == 0 and end == 1.
Fix code will like:
// at file MemoryModule.c line 561
while (end > start) {
WORD entryName;
middle = (start + end) >> 1;
entryName = (WORD) entries[middle].Name;
if (check < entryName) {
// _change below line_****
end = (end != middle ? middle : middle - 1);
} else if (check > entryName) {
// _change below line_****
start = (start != middle ? middle : middle + 1);
} else {
result = &entries[middle];
break;
}
}
The block at file MemoryModule.c line 601 should be fixed too.
I'm getting this warning:
warning C4996: 'wcsncpy': This function or variable may be unsafe. Consider using wcsncpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
Hi,
Thanks for awesome project, Is great if ported to C#.
I'm using the latest version of MemoryModule (f02a8e6).
To reproduce, replace SampleDLL.cpp
with:
class Callable
{
public:
virtual int call() { return 0; }
};
Callable * GetCallable()
{
static Callable callable;
return &callable;
}
int i = GetCallable()->call();
(this should be valid C++ code as far as I'm aware)
and DllLoader.cpp
with:
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <malloc.h>
#include "../../MemoryModule.h"
#define DLL_FILE TEXT("..\\SampleDLL\\SampleDLL.dll")
void LoadFromFile(void)
{
HINSTANCE handle = LoadLibrary(DLL_FILE);
if (handle == NULL)
return;
FreeLibrary(handle);
}
void LoadFromMemory(void)
{
FILE *fp;
unsigned char *data=NULL;
size_t size;
HMEMORYMODULE handle;
fp = _tfopen(DLL_FILE, _T("rb"));
if (fp == NULL)
{
_tprintf(_T("Can't open DLL file \"%s\"."), DLL_FILE);
goto exit;
}
fseek(fp, 0, SEEK_END);
size = ftell(fp);
data = (unsigned char *)malloc(size);
fseek(fp, 0, SEEK_SET);
fread(data, 1, size, fp);
fclose(fp);
handle = MemoryLoadLibrary(data);
if (handle == NULL)
{
_tprintf(_T("Can't load library from memory.\n"));
goto exit;
}
MemoryFreeLibrary(handle);
exit:
if (data)
free(data);
}
int main(int argc, char* argv[])
{
//LoadFromFile();
LoadFromMemory();
return 0;
}
If LoadFromFile()
is run, the program exits with 0.
However, if LoadFromMemory()
is run, it crashes with:
Exception thrown at 0x0008146E in DllLoader.exe: 0xC0000005: Access violation reading location 0x00000000.
Stacktrace:
0008146e() Unknown
[Frames below may be incorrect and/or missing]
ucrtbased.dll!__initterm�() Unknown
00082d41() Unknown
00082be9() Unknown
00082fbd() Unknown
000831df() Unknown
> DllLoader.exe!MemoryLoadLibraryEx(const void * data, void * (const char *, void *) * loadLibrary, int (...) * (void *, const char *, void *) * getProcAddress, void (void *, void *) * freeLibrary, void * userdata) Line 560 C
DllLoader.exe!MemoryLoadLibrary(const void * data) Line 433 C
DllLoader.exe!LoadFromMemory() Line 42 C++
DllLoader.exe!main(int argc, char * * argv) Line 60 C++
DllLoader.exe!invoke_main() Line 74 C++
DllLoader.exe!__scrt_common_main_seh() Line 264 C++
DllLoader.exe!__scrt_common_main() Line 309 C++
DllLoader.exe!mainCRTStartup() Line 17 C++
kernel32.dll!@BaseThreadInitThunk@12�() Unknown
ntdll.dll!___RtlUserThreadStart@8�() Unknown
ntdll.dll!__RtlUserThreadStart@8�() Unknown
Line 560 in MemoryModule.c
:
// notify library about attaching to process
BOOL successfull = (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, 0);
Strangely enough, if both LoadFromLibrary()
and LoadFromMemory()
are run (and in that order!), there is no crash.
Hi there- great library. One little comment... if the project settings are 'Unicode', it doesn't work because LoadLibraryW is called. Changing the MemoryModule.c 'LoadLibrary' call to 'LoadLibraryA' patches things up, at least on my system (MSVC10 & XP SP3)
I recently tried to load a DLL that had a dependency on a Windows Side-by-side assembly, specifically MSVCRT90.DLL. Due to the way that WinSxS assemblies are loaded from the assembly cache by the Windows loader, the LoadLibrary() call for MSVCRT90.DLL in BuildImportTable() returned NULL.
I'm looking into a way this could be resolved, and right now it appears one solution is to extract and parse a DLL's manifest to look for WinSxS dependencies, set the activation context, call LoadLibrary(), then unset the activation context[1][2]. The only problem with that is that you need to write a temporary file to disk in order to set the activation context, which kind of defeats the memory-only purpose of MemoryModule. And I suppose another problem with this solution is that the OS must have the specific version of the WinSxS dependency installed in the assembly cache.
I'll see if I can find another solution, but I just wanted to flag this issue for now.
[1] http://www.joachim-bauch.de/tutorials/loading-a-dll-from-memory/comment-page-1/#comment-28901
[2] https://stackoverflow.com/questions/11175430/resolving-pe-sxs-imports-windows
Closed.
Hi,
i get the following errors while building current master:
y:\fancycode-memorymodule-d2e86ce\memorymodule.c(179) : error C2065: 'IMAGE_SIZEOF_BASE_RELOCATION' : undeclared identifier
y:\fancycode-memorymodule-d2e86ce\memorymodule.c(180) : error C2065: 'IMAGE_SIZEOF_BASE_RELOCATION' : undeclared identifier
build environment:
Microsoft Visual Studio 2008
Version 9.0.21022.8 RTM
Microsoft .NET Framework
Version 3.5 SP1
am i missing something?
Test user32.dll with Win7 x64, failed both 32 and 64.
Is there a chance to debug functions which were loaded from memory?
I guess the debugger is not notified about the dynamically loaded module.
Great library!
Thank you 👍
Hi,
first of all great job, this module works really well with all the DLL executables I created.
However I now want to execute EXE executables from memory with arguments. I saw your code is also able to execute EXE files, but I don't know were I should provide the arguments.
Could you tell me the right way to do this ?
It currently appears that MemoryModule doesn't support loading modules with delay-loaded dependencies (see here).
Currently the BuildImportTable
function fails due to the following handle returning NULL:
HCUSTOMMODULE handle = module->loadLibrary((LPCSTR)(codeBase + importDesc->Name), module->userdata);
This is expected with a delay-loaded module, and should probably be handled appropriately. This was tested with python27.dll, the Python 2.7 release library.
my code:
typedef BOOL (WINAPI* P_EnumWindows)(
In WNDENUMPROC lpEnumFunc,
In LPARAM lParam
);
P_EnumWindows g_pEnumWindows = NULL;
BOOL CALLBACK EnumWndProc(HWND hWnd, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
TCHAR lpWinTitle[MAX_PATH] = {0};
::GetWindowText(hWnd,lpWinTitle,MAX_PATH - 1);
return TRUE;
}
void TestReloadUser32(void)
{
FILE *fp;
unsigned char *data=NULL;
size_t size;
HMEMORYMODULE handle;
fp = _tfopen(_T("c:\\windows\\system32\\user32.dll"), _T("rb"));
if (fp == NULL)
{
_tprintf(_T("Can't open DLL file \"%s\"."), DLL_FILE);
goto exit;
}
fseek(fp, 0, SEEK_END);
size = ftell(fp);
data = (unsigned char *)malloc(size);
fseek(fp, 0, SEEK_SET);
fread(data, 1, size, fp);
fclose(fp);
handle = MemoryLoadLibrary(data);//!!!failed
if (handle == NULL)
{
_tprintf(_T("Can't load library from memory.\n"));
goto exit;
}
//if commented the following code at MemoryLoadLibraryEx (line 441),
//it will crash at g_pEnumWindows(EnumWndProc,NULL) with(0xC0000005)
//ExecuteTLS(result);
//// get entry point of loaded library
//if (result->headers->OptionalHeader.AddressOfEntryPoint != 0) {
// DllEntry = (DllEntryProc) (code + result->headers->OptionalHeader.AddressOfEntryPoint);
// // notify library about attaching to process
// successfull = (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, 0);
// if (!successfull) {
// SetLastError(ERROR_DLL_INIT_FAILED);
// goto error;
// }
// result->initialized = 1;
//}
g_pEnumWindows = (P_EnumWindows)MemoryGetProcAddress(handle,"EnumWindows");
if (NULL == g_pEnumWindows)
{
goto exit;
}
g_pEnumWindows(EnumWndProc,NULL);//here!!
exit:
if (data)
free(data);
}
MemoryLibrary.c:250
You make the incorrect assumption that LoadLibrary() returns INVALID_HANDLE_VALUE on failure. It actually returns NULL. INVALID_HANDLE_VALUE is 0xffffffff.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms684175%28v=vs.85%29.aspx
"If the specified module is a DLL that is not already loaded for the calling process, the system calls the DLL's DllMain function with the DLL_PROCESS_ATTACH value. If DllMain returns TRUE, LoadLibrary returns a handle to the module. If DllMain returns FALSE, the system unloads the DLL from the process address space and LoadLibrary returns NULL. It is not safe to call LoadLibrary from DllMain. For more information, see the Remarks section in DllMain."
The linked patch fixes 4 compiler warning when building with VS2008 x64.
http://bazaar.launchpad.net/~kovid/calibre/trunk/revision/13802
Hi,
When I protect DLL with VMProtect the MemoryModule could not be loaded, I attached a sample.
If stdint.h
in MemoryModule.c is unnecessary, it is nice to remove it to enable build with VC++ 9.0 (VS2008) which is still actively used by Python 2.7.
I'm building and roughly testing MemoryModule with removing the stdint.h
and it seems to work without problem on VC++ 9.0, 10.0 and 14.0.
Compilation of MemoryModule (no stdint.h
) with VC++ 9.0 32bit
https://ci.appveyor.com/project/sakurai_youhei/pymemorymodule/build/25/job/shv70h2w1pfxbakv#L79
Compilation of MemoryModule (no stdint.h
) with VC++ 9.0 64bit
https://ci.appveyor.com/project/sakurai_youhei/pymemorymodule/build/25/job/lac6j3tgcupiruyr#L85
On x64 builds with VS 2015 the ALIGN_DOWN macro produces wrong addresses if the address is larger than 2^32. VS 2015 also produces a warning
MemoryModule.c(247): warning C4319: '~': zero extending 'DWORD' to 'uintptr_t' of greater size
The same applies to ALIGN_VALUE_UP.
A possible solution could be replacing the definition of ALIGN_DOWN and ALIGN_VALUE_UP by
...
I run the DLLoader on win7 64bits, however, when I see the result of resourceInfo
(resourceInfo = FindResource(handle, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION);), It is )0x000000.. What is wrong ?
Maybe I'm just not looking in the right places but it looks like the reference counting is not implemented.
The system maintains a per-process reference count on all loaded modules. Calling LoadLibrary increments the reference count. Calling the FreeLibrary or FreeLibraryAndExitThread function decrements the reference count. The system unloads a module when its reference count reaches zero or when the process terminates (regardless of the reference count).
(from https://msdn.microsoft.com/en-us/library/windows/desktop/ms684175(v=vs.85).aspx)
I'm not sure how this would work without some more information passed into MemoryLoadLibraryEx but it definitely looks like a big missing piece.
FinalizeSections will fail if the allocated memory spans over the address 0x100000000 (4GB) since the addresses in the IMAGE_SECTION_HEADER are only 32-bit values.
I could fix it by putting the following code after the allocation of the variable "code":
#ifdef _WIN64
// check that memory-block does not span over the 4GB border
if(code < (LPVOID)0x100000000 && code + alignedImageSize >= (LPVOID)0x100000000)
{
auto old_code = code;
code = (unsigned char *)allocMemory(NULL,
alignedImageSize,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE,
userdata);
freeMemory(old_code, 0, MEM_RELEASE, userdata);
if(code == NULL) {
SetLastError(ERROR_OUTOFMEMORY);
return NULL;
}
}
#endif
I am having issues compiling with this with gcc-4.8
my config line is CC=i586-mingw32-gcc CXX=i586-mingw32-g++ cmake ../
but when i run make I get errs from the src.
MemoryModule.c:112:58: error: ‘uintptr_t’ undeclared (first use in this function)
section->Misc.PhysicalAddress = (DWORD) (uintptr_t) dest;
Just a heads up — On line 249 of MemoryModule.c you have the line:
HMODULE handle = LoadLibrary((LPCSTR) (codeBase + importDesc->Name));
If you are compiling for Unicode, this line fails. Unicode define is using LoadLibraryW() which expects a LPCWSTR as the first parameter. Simple fix is to explicitly use LoadLibraryA(), so the line would end up looking like this:
HMODULE handle = LoadLibraryA((LPCSTR) (codeBase + importDesc->Name));
Hello! First off, I have to say that this repository has been absolutely amazing for me, allowing me to crack a DLL loading nut that has been bedeviling me for many years. It "just works", which is pretty awesome.
That said, I'm preparing to make publicly available a library that uses MemoryModule quite a bit. I had to revamp the ReadLibrary
function to remove the macro definition (yuck), to read something like this
/// Read the binary data from the shared library file as a blob of memory
/// Taken from MemoryModule, under MPL 2.0 license
void* ReadLibrary(const std::string &fname, size_t &pSize) {
...
};
The guts of this function are basically what was in ReadLibrary
before with some slight modifications to reduce some code smell.
Now my question is this: although I do not make any other modifications to the MemoryModule code other than making this function derived from your function, I'm a bit unclear on the terms of the MPLv2. I plan to make my library open-source (and therefore this function would be open-source too), which should fulfill the requirements of MPLv2, right? If we are unable to open-source the library, how much disclosure of source is required? I am of course fine with providing the source for MemoryModule, even if I can't provide the source for my library. The plan is to cite your work in our documentation as well.
There was a memory leak when the new thread created using the dll function loading from memory. I found that is an artical that: When the dll loaded from memory ,the DllMain() doesn't receive DLL_THREAD_ATTACH and DLL_THREAD_DETACH notifications. What‘s the reason, Could it be fixed?
The reference is:Loading Win32/64 DLLs "manually" without LoadLibrary()
https://www.codeproject.com/tips/430684/loading-win-dlls-manually-without-loadlibrary
I've tried and it didn't work, but I may have been doing it wrong.
Can not load VC6 compiled EXE
MemoryFindResource always return NULL in both 32 and 64-bit.
In the dll
CString getAppPath()
{
static CString path = L"D:\test\dir0"
return path;
}
then if load the dll from memory and call the function, the result will be a invalid object.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.