Portál AbcLinuxu, 30. dubna 2025 15:28
Občas se hodí zavolat vlastní verzi ioctl() bez rekompilace binárky (např. pro ladící účely a teprve poté zavolat reálné ioctl()), jako ukázku přikládám návrat MAC adresy:
$ ./get_mac
00:0a:e4:a9:36:d8
$ LD_PRELOAD="libwrap_ioctl.so.1.0" ./get_mac
0a:0b:0c:0d:0e:0f
Makefile:
all: libwrap_ioctl.so get_mac
libwrap_ioctl.so: ioctlw.c
gcc -Wall -fPIC -shared -Wl,-soname,libwrap_ioctl.so.1 \
-I/usr/lib/oss/include -I/usr/include \
-o libwrap_ioctl.so.1.0 -ldl ioctlw.c
get_mac: get_mac.c
gcc -Wall -o get_mac get_mac.c
ioctlw.c:
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <net/if.h>
#define SIOCGIFHWADDR 0x8927 /* Get hardware address */
static int (*next_ioctl)(int fd, int request, void *data) = NULL;
int ioctl(int fd, int request, void *data)
{
struct ifreq ifr;
char *msg;
if (request == SIOCGIFHWADDR) {
memcpy(&ifr, data, sizeof(struct ifreq));
ifr.ifr_hwaddr.sa_data[0] = 0x0A;
ifr.ifr_hwaddr.sa_data[1] = 0x0B;
ifr.ifr_hwaddr.sa_data[2] = 0x0C;
ifr.ifr_hwaddr.sa_data[3] = 0x0D;
ifr.ifr_hwaddr.sa_data[4] = 0x0E;
ifr.ifr_hwaddr.sa_data[5] = 0x0F;
memcpy(data, &ifr, sizeof(struct ifreq));
return 0;
}
if (next_ioctl == NULL) {
fprintf(stderr, "ioctl: wrapping ioctl\n");
fflush(stderr);
next_ioctl = dlsym(RTLD_NEXT, "ioctl");
fprintf(stderr, "next_ioctl = %p\n", next_ioctl);
fflush(stderr);
if ((msg = dlerror()) != NULL) {
fprintf(stderr, "ioctl: dlopen failed: %s\n", msg);
fflush(stderr);
exit(1);
}
else {
fprintf(stderr, "ioctl: wrapping done\n");
}
fflush(stderr);
}
return next_ioctl(fd, request, data);
}
//void *dlsym(void *handle, const char *symbol)
//{
// void* result = __libc_dlsym(handle, symbol);
//
// printf("%s\n", symbol);
//
// return result;
//}
get_mac.c
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
int main()
{
int fd;
struct ifreq ifr;
fd = socket(AF_INET, SOCK_DGRAM, 0);
ifr.ifr_addr.sa_family = AF_INET;
strncpy(ifr.ifr_name, "eth0", IFNAMSIZ-1);
ioctl(fd, SIOCGIFHWADDR, &ifr);
close(fd);
/* display result */
printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
(unsigned char)ifr.ifr_hwaddr.sa_data[0],
(unsigned char)ifr.ifr_hwaddr.sa_data[1],
(unsigned char)ifr.ifr_hwaddr.sa_data[2],
(unsigned char)ifr.ifr_hwaddr.sa_data[3],
(unsigned char)ifr.ifr_hwaddr.sa_data[4],
(unsigned char)ifr.ifr_hwaddr.sa_data[5]);
return 0;
}
Zdroje:
Using LD_PRELOAD libraries and glibc backtrace function for debugging
Simple sample of getting MAC address information
Wrapping dlsym()
Tiskni
Sdílej:
Funkce ioctl() je v libc:
$ readelf -a /lib/i686/cmov/libc.so.6 |grep ioctl
1361: 000d8040 63 FUNC WEAK DEFAULT 11 ioctl@@GLIBC_2.0
Co říká:
$ ldd tvoje_binarka
linux-gate.so.1 => (0xb7f30000)
libc.so.6 => /lib/i686/cmov/libc.so.6 (0xb7db8000)
/lib/ld-linux.so.2 (0xb7f31000)
Myslím, že i Tvá binárka bude využívat libc, i když ostatní knihovny jsou přilinkovány staticky.
Žiaľ, nie. Nesie so sebou vlastnú C knižnicu, ldd na ňu vôbec nefunguje.
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.