artesanía gancho binaria del núcleo de Linux - un ejemplo práctico, el recuento de iptables DROP

artículo anterior, he mostrado una demo, para lograr un recuento tanto para la lógica de gancho binaria:
https://blog.csdn.net/dog250/article/details/105205966

Pero después de todo, sólo una demostración de demostración, necesito utilizar un ejemplo práctico puede ser utilizado para mostrar las cosas más interesantes.

En el presente documento a un ejemplo práctico, contando los iptables DROP descarta los paquetes de datos binarios gancho.

Contamos con la cadena INPUT descartar el paquete como un ejemplo para implementar esta función. En primer lugar, mirada ip_local_deliver funciones de desmontaje:

crash> dis ip_local_deliver
...
0xffffffff81561eb5 <ip_local_deliver+165>:      movq   $0xffffffff81561ad0,-0x18(%rbp)
0xffffffff81561ebd <ip_local_deliver+173>:      callq  0xffffffff815586a0 <nf_hook_slow>
0xffffffff81561ec2 <ip_local_deliver+178>:      cmp    $0x1,%eax
0xffffffff81561ec5 <ip_local_deliver+181>:      jne    0xffffffff81561e69 <ip_local_deliver+89>
0xffffffff81561ec7 <ip_local_deliver+183>:      jmp    0xffffffff81561e5f <ip_local_deliver+79>
0xffffffff81561ec9 <ip_local_deliver+185>:      nopl   0x0(%rax)
...

Vemos, valor de retorno nf_hook_slow determina los paquetes de datos no están siendo DROP, este es nuestro punto de gancho.

En cuanto a cómo saber es modificar ip_local_deliver, es totalmente familiarizado con el código del núcleo.

enganchar 173 bytes se compensa, 5 bytes pueden enganchar longitud:

  • El nf_hook_slow llamada cambiado a llamar a nuestras propias funciones de código auxiliar.
  • Llamada nf_hook_slow lleva a cabo en nuestra función trozo.
  • Llame relativa nf_hook_slow ajuste de la desviación.

Tratamos de lograrlo, códigos de barras directamente en el módulo:

// 注意,本文的此例未考虑并发问题,正规的做法应该采用percpu变量或者atomic变量
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/cpu.h>

char *stub;
char *addr = NULL;

// 传入ip_local_deliver的地址
static unsigned long laddr = 0xffffffffa0267000;
module_param(laddr, ulong, 0644);

// 计数INPUT链上的被DROP的数据包的数量
static unsigned int counter = 0;
module_param(counter, int, 0444);

void test_stub1(void) __attribute__ ((aligned (1024)));
void test_stub2(void) __attribute__ ((aligned (1024)));
void test_stub1(void)
{
	printk("yes\n");
}
void test_stub2(void)
{
	printk("yes yes\n");
}

#define FTRACE_SIZE   	5
#define POKE_OFFSET		173
#define POKE_LENGTH		5
#define COND_LENGTH		5
#define COUNTE_LENGTH	8

static void *(*_text_poke_smp)(void *addr, const void *opcode, size_t len);
static struct mutex *_text_mutex;

static unsigned int pos, target;
static int __init hotfix_init(void)
{
	unsigned char e8_call[POKE_LENGTH];
	unsigned char incl[COUNTE_LENGTH];
	unsigned char cond[COND_LENGTH];
	s32 offset, i;
	u32 low32 = (unsigned int)(((unsigned long)&counter) & 0xffffffff);

	addr = (void *)laddr;

	_text_poke_smp = (void *)0xffffffff8163e1f0;
	_text_mutex = (void *)0xffffffff81984920;

	stub = (void *)test_stub1;

	// 两个函数的call地址偏移
	offset = (s32)((long)stub - (long)addr - FTRACE_SIZE);
	// 两个函数指令相对偏移
	pos = (unsigned int)((long)stub - (long)addr);

	_text_poke_smp(&stub[0], &addr[POKE_OFFSET], POKE_LENGTH);

	// 调节校准call nf_hook_slow的相对地址偏移
	target = *((unsigned int *)&addr[POKE_OFFSET + 1]);
	target -= pos;
	target += POKE_OFFSET;
	_text_poke_smp(&stub[1], &target, sizeof(target));

	// 填充条件判断:只有返回DROP才会被计数
	cond[0] = 0x83; // cmp $0x1, %eax
	cond[1] = 0xf8;
	cond[2] = 0x01;
	cond[3] = 0x74; // jz $ret
	cond[4] = 0x07; // skip "incl $counter"
	_text_poke_smp(&stub[POKE_LENGTH], &cond, COND_LENGTH);

	// 插入的指令中需要save/restore寄存器,但这里简单,略过
	incl[0] = 0xff; // incl $counter
	incl[1] = 0x04;
	incl[2] = 0x25;
	(*(u32 *)(&incl[3])) = low32;
	incl[7] = 0xc3; // retq
	_text_poke_smp(&stub[POKE_LENGTH + COND_LENGTH], &incl, 8);

	// call比jmp方便,可以自动帮忙return,不然还要自己jmp回来,但是代价是push/pop
	e8_call[0] = 0xe8;
	(*(s32 *)(&e8_call[1])) = offset - POKE_OFFSET;
	for (i = 5; i < POKE_LENGTH; i++) {
		e8_call[i] = 0x90; // nop 占位符
	}
	get_online_cpus();
	mutex_lock(_text_mutex);
	_text_poke_smp(&addr[POKE_OFFSET], e8_call, POKE_LENGTH);
	mutex_unlock(_text_mutex);
	put_online_cpus();

	return 0;
}

static void __exit hotfix_exit(void)
{
	target -= POKE_OFFSET;
	target += pos;
	_text_poke_smp(&stub[1], &target, sizeof(target));
	get_online_cpus();
	mutex_lock(_text_mutex);
	_text_poke_smp(&addr[POKE_OFFSET], &stub[0], POKE_LENGTH);
	mutex_unlock(_text_mutex);
	put_online_cpus();
}

module_init(hotfix_init);
module_exit(hotfix_exit);
MODULE_LICENSE("GPL");

Bueno, módulos de carga, para ver los resultados.

En primer lugar, añadimos una regla de iptables:

[root@localhost ~]# iptables -A INPUT -i lo -j DROP

A continuación, confirme el contador a cero:

[root@localhost timer]# cat /sys/module/nowa/parameters/counter
0
[root@localhost ~]# iptables -t filter -L -v
Chain INPUT (policy ACCEPT 37 packets, 2628 bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 DROP       all  --  lo     any     anywhere             anywhere

Vamos, iniciar tráfico, luego se detuvo después de un momento:

[root@localhost ~]# telnet 127.0.0.1 23
Trying 127.0.0.1...
^@^C
[root@localhost ~]#

Comprobar contador es correcta:

[root@localhost ~]# cat /sys/module/nowa/parameters/counter
7
[root@localhost ~]# iptables -t filter -L -v
Chain INPUT (policy ACCEPT 103 packets, 7336 bytes)
 pkts bytes target     prot opt in     out     source               destination
    7   420 DROP       all  --  lo     any     anywhere             anywhere

OK, contador binario gancho contador consistente y iptables en sí.


Bueno, después de la finalización de todo esto, pensamos detenidamente, hay muchas cuestiones pendientes:

  • ¿Cómo hacer si el desplazamiento no está dentro del alcance de 32 bits? Que se necesita un salto absoluto de 64 bits.
  • Cuando la lógica compleja requiere registro adicional, es necesario guardar / restauración de todos los registros, y la función original para evitar conflictos.
  • ...

En resumen, se trata de una programación de código binario de máquina directa. Debe tenerse en cuenta que esto es sólo artesanos o trabajadores malabares, así que jugar en el entorno de producción, el gerente será dis. Obediente con kpatch ella.


Wenzhou zapatos mojados, el agua de lluvia no será grasa.

Liberadas 1580 artículos originales · ganado elogios 5111 · Vistas 11.130.000 +

Supongo que te gusta

Origin blog.csdn.net/dog250/article/details/105206753
Recomendado
Clasificación