Last active
April 15, 2024 18:00
-
-
Save Lekensteyn/c8d41c02d118aa40bc100020efde3696 to your computer and use it in GitHub Desktop.
Make libnvidia-ml.so (nvidia-smi) write plaintext debug logs (mirror of https://lekensteyn.nl/files/nvml-debugdump.c)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Make libnvidia-ml.so (nvidia-smi) write plaintext debug logs. | |
* | |
* Usage: | |
* | |
* gcc -shared -fPIC -ldl nvml-debugdump.c -o nvml-debugdump.so | |
* LD_PRELOAD=./nvml-debugdump.so nvidia-smi --debug=debug.log -q | |
* | |
* For other NVML applications, set env var __NVML_DBG_FILE=debug.log | |
* | |
* How it works: the observed call sequence is: vsnprintf, fwrite, fflush where | |
* vsnprintf and fwrite apparently share the same pointer (in-place encryption | |
* probably happens netween vsnprintf and fwrite). This library simply copies | |
* data at vsnprintf time and replaces the encrypted data at fwrite time. | |
*/ | |
#define _GNU_SOURCE /* for RTLD_NEXT */ | |
#include <dlfcn.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
static char *last_str_ptr; | |
static char last_str[2048]; | |
static int (*vsnprintf_real)(char *str, size_t size, const char *format, va_list ap); | |
int vsnprintf(char *str, size_t size, const char *format, va_list ap) | |
{ | |
if (!vsnprintf_real) { | |
vsnprintf_real = dlsym(RTLD_NEXT, "vsnprintf"); | |
if (!vsnprintf_real) { | |
fprintf(stderr, "vsnprintf: %s\n", dlerror()); | |
abort(); | |
} | |
} | |
int r = vsnprintf_real(str, size, format, ap); | |
// reduce false matches, logging always seem to happen with fixed size. | |
if (size != 2048 || r <= 0) { | |
return r; | |
} | |
// Assume that the debug log is written from one function (such that the | |
// address of the caller is always the same). This case was not seen yet, | |
// but just in case... | |
void *ret_addr = __builtin_return_address(0); | |
static void *expected_caller_addr; | |
if (expected_caller_addr != ret_addr) { | |
if (!expected_caller_addr) { | |
expected_caller_addr = ret_addr; | |
} else { | |
// address mismatch, probably a different function | |
return r; | |
} | |
} | |
memcpy(last_str, str, r + 1); | |
last_str_ptr = str; | |
return r; | |
} | |
static size_t (*fwrite_real)(const void *ptr, size_t size, size_t nmemb, FILE *stream); | |
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) | |
{ | |
if (!fwrite_real) { | |
fwrite_real = dlsym(RTLD_NEXT, "fwrite"); | |
if (!fwrite_real) { | |
fprintf(stderr, "fwrite: %s\n", dlerror()); | |
abort(); | |
} | |
} | |
if (ptr == last_str_ptr) { | |
ptr = last_str; | |
last_str_ptr = NULL; | |
} | |
return fwrite_real(ptr, size, nmemb, stream); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Alternative way, we could decrypt the log directly
`
static uint32_t x = 0, y = 0, z = 0,
w = 0, v = 0, d = 0;
void xorwow_init_seed() {
x = 0x0D3DAECB8, y = 0x1D4D4848, z = 0x0AA7B8E81,
w = 0x23CC0EC3, v = 0x7645F3ED, d = 0x0E44A4F49;
}
void xorwow_encrypt(char* buffer, int len) {
int i = 0;
for(i=0 ; i < len; i++){
uint32_t t = (x^(x>>2)); x = y; y = z; z = w; w = v; v = (v^(v<<4))^(t^(t<<1));
uint32_t r = ((d+=362437)+v);
buffer[i] += (r & 0xFF);
}
return;
}
`