Skip to content

Instantly share code, notes, and snippets.

@yurynix
Last active May 25, 2022 15:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yurynix/3122594894e88f43dc49c5d3265c0561 to your computer and use it in GitHub Desktop.
Save yurynix/3122594894e88f43dc49c5d3265c0561 to your computer and use it in GitHub Desktop.
Intercept open calls
gcc -shared -fPIC inject_tcp.c -o inject.so -ldl
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
//#include <unistd.h>
//#include <sys/stat.h>
#include <stdarg.h>
#include <curl/curl.h>
#include <stdlib.h>
extern ssize_t write(int, const void *, size_t); // from unistd.h
//
// returns:
// 0 - file does not exists
// 1 - file exists
// -1 - failure
int is_remote_file_exists(const char* url) {
CURL *curl = curl_easy_init();
if (curl) {
/* First set the URL that is about to receive our POST. This URL can
just as well be a https:// URL if that is what should receive the
data. */
curl_easy_setopt(curl, CURLOPT_URL, url);
/* get us the resource without a body - use HEAD! */
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
/* Perform the request */
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
return -1;
}
long http_code = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
printf("status code: %ld\n", http_code);
/* always cleanup */
curl_easy_cleanup(curl);
return http_code == 200 ? 1 : 0;
}
return -1;
}
typedef int (*orig_open_f_type)(const char *pathname, int flags);
orig_open_f_type orig_open64 = NULL;
typedef long int (*orig_syscall_type)(long int syscallNumber, ...);
orig_syscall_type orig_syscall = NULL;
void writeLogToFile(const char *logline) {
// FILE *log = fopen("/tmp/trace.txt", "a+");
// fprintf(log, "%s\n", logline);
// fclose(log);
}
int endsWith(const char *str, const char *suffix)
{
if (!str || !suffix)
return 0;
size_t lenstr = strlen(str);
size_t lensuffix = strlen(suffix);
if (lensuffix > lenstr)
return 0;
return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0;
}
int open64(const char *pathname, int flags) {
printf("open64('%s', %d)\n",pathname, flags);
writeLogToFile(pathname);
// https://sudonull.com/post/120265-Practical-use-of-LD_PRELOAD-or-function-substitution-in-Linux
//if (endsWith(pathname, ".js")) {
if (strstr(pathname, "node_modules")) {
//opening tcp socket
struct sockaddr_in servaddr;
int socketfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // addr
servaddr.sin_port = htons(32000); // port
printf("Before connect\n");
if (connect(socketfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == 0) {
printf("[Open] FD: %d TCP Connected\n", socketfd);
write(socketfd, pathname, strlen(pathname));
return socketfd;
} else {
printf("[Open] FD: %d TCP Connection failed!\n", socketfd);
// let it fallback below
}
}
int fd = orig_open64(pathname,flags);
printf("open64('%s') => %d\n", pathname, fd);
return fd;
}
/*
int __fxstat64(int ver, int fildes, struct stat64 * stat_buf) {
printf("__fxstat64 %d %d\n", ver, fildes);
return 0;
}
int __xstat64(int ver, const char * path, struct stat64 * stat_buf) {
printf("__xstat64(%d, %s, %lx)\n", ver, path, (unsigned long)stat_buf);
return 0;
}
*/
int stat64(int ver, const char * path, void * stat_buf) {
printf("stat(%d, %s, %lx)\n", ver, path, (unsigned long)stat_buf);
return 0;
}
struct uv__statx_timestamp {
int64_t tv_sec;
uint32_t tv_nsec;
int32_t unused0;
};
struct uv__statx {
uint32_t stx_mask;
uint32_t stx_blksize;
uint64_t stx_attributes;
uint32_t stx_nlink;
uint32_t stx_uid;
uint32_t stx_gid;
uint16_t stx_mode;
uint16_t unused0;
uint64_t stx_ino;
uint64_t stx_size;
uint64_t stx_blocks;
uint64_t stx_attributes_mask;
struct uv__statx_timestamp stx_atime;
struct uv__statx_timestamp stx_btime;
struct uv__statx_timestamp stx_ctime;
struct uv__statx_timestamp stx_mtime;
uint32_t stx_rdev_major;
uint32_t stx_rdev_minor;
uint32_t stx_dev_major;
uint32_t stx_dev_minor;
uint64_t unused1[14];
};
long int syscall(long int syscallNumber, ...) {
printf("syscall %ld ", syscallNumber);
if (syscallNumber == 291) {
va_list args;
va_start(args, syscallNumber);
int dirfd = va_arg(args, int);
char * path = va_arg(args, char *);
int flags = va_arg(args, int);
unsigned int mask = va_arg(args, unsigned int);
struct uv__statx* statxbuf = va_arg(args, struct uv__statx*);
printf("path: %s ", path);
va_end(args);
if (endsWith(path, "node_modules")) {
// https://docs.huihoo.com/doxygen/linux/kernel/3.7/include_2uapi_2linux_2stat_8h_source.html
// We tell it's a directory
statxbuf->stx_mode = 0040000;
printf("Return OK and IS_DIR\n");
return 0;
} else {
printf("\n");
}
char url_prefix[] = "http://localhost:3201";
char * url = malloc(sizeof(char) * (strlen(path) + strlen(url_prefix) + 1));
strncpy(url, url_prefix, strlen(url_prefix));
strncpy(url + strlen(url_prefix), path, strlen(path) + 1);
printf("url: %s\n", url);
if (is_remote_file_exists(url) == 1) {
free(url);
return 0;
}
free(url);
} else {
printf("\n");
}
__builtin_return(
__builtin_apply(
(void(*)())orig_syscall, __builtin_apply_args(), 512));
}
__attribute__((constructor)) void init() {
printf("Intercepting open() calls\n");
if (orig_open64 == NULL) {
orig_open64 = (orig_open_f_type)dlsym(RTLD_NEXT, "open64");
}
if (orig_syscall == NULL) {
orig_syscall = (orig_syscall_type)dlsym(RTLD_NEXT, "syscall");
}
}
const net = require('node:net');
const server = net.createServer((c) => {
// 'connection' listener.
console.log('client connected');
c.on('end', () => {
console.log('client disconnected');
});
c.write('{"main":"pizdetz.js", "name": "@yarnpkg/lockfile", "version": "1.2.3"}\r\n', () => c.end());
c.on('data', d => console.log('data', d.toString()));
//c.end();
});
server.on('error', (err) => {
throw err;
});
server.listen(32000, () => {
console.log('server bound');
});
const http = require('node:http');
// Create a local server to receive data from
const httpServer = http.createServer((req, res) => {
console.log('req', req.url);
res.writeHead(404, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
data: 'Hello World!'
}));
});
httpServer.listen(3201);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment