Применение мониторинга ядра Linux при атаке и защите Android
Применение мониторинга ядра Linux при атаке и защите Android

существуют При ежедневном анализе внешнего программного обеспечения,Появляется все больше и больше средств защиты от отладки/инъекций.,Доиспользоватьизна основе frida Легкая песочница APP Выполните комплексный мониторинг и обход. Эта статья представляет собой исследование и практику таких решений.

фон

Чтобы обеспечить всесторонний мониторинг Android-приложения, необходимо знать, к каким файлам обращается/открывает целевое приложение и какие операции выполняются, а возвращаемые результаты этих операций можно изменять и контролировать. Интуитивная идея состоит в том, чтобы использовать libc в качестве унифицированного интерфейса для сбора данных о поведении приложений, например, взять на себя управление open/openat/faccess/fstatat для реализации мониторинга доступа к файлам и дальнейшего перенаправления файлов.

Однако сегодня многие умные подкрепления APP Оба использования имеют встроенную сборку системных вызовов для обхода libc Чтобы добиться темноты в Чэнцане, binary уровень плюс обфускация потока управления, цветочные инструкции, шифрование кода и даже VMP зрелая из мер защиты,позволяют идентифицировать такие скрытыевызовстать очень трудным。Неизвестный исследователь безопасностиоднажды сказал:

Never to wrestle with a pig. You get dirty, and besides, the pig likes it.

Поэтому нам следует не бороться с производителями арматуры на прикладном уровне, а искать точки прорыва и достигать цели четырьмя способами. Конечно, если вы хотите только потренироваться, вы также можете отодрать виртуальную машину вручную. :)

Существующие решения

Прежде чем представить технологию мониторинга ядра, давайте сначала рассмотрим некоторые существующие решения и их недостатки.

strace

strace да Linux Известный в Китае инструмент отслеживания системных вызовов пользовательского режима. Вы можете ввести имя и параметры системного вызова, выполняемого целевым процессом. Он часто используется для быстрой отладки и диагностики приложений. след Пример вывода выглядит следующим образом:

Язык кода:javascript
копировать
$ strace echo evilpan
execve("/usr/bin/echo", ["echo", "evilpan"], 0x7fe55d5d18 /* 56 vars */) = 0
brk(NULL)                               = 0x57b1bd2000
faccessat(AT_FDCWD, "/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=19285, ...}) = 0
mmap(NULL, 19285, PROT_READ, MAP_PRIVATE, 3, 0) = 0x79aecf8000
close(3)                                = 0
openat(AT_FDCWD, "/lib/aarch64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0\267\0\1\0\0\0p\16\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0777, st_size=1439544, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x79aecf6000
mmap(NULL, 1511520, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x79aeb5e000
mprotect(0x79aecb7000, 61440, PROT_NONE) = 0
mmap(0x79aecc6000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x158000) = 0x79aecc6000
mmap(0x79aeccc000, 12384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x79aeccc000
close(3)                                = 0
mprotect(0x79aecc6000, 16384, PROT_READ) = 0
mprotect(0x5787f5f000, 4096, PROT_READ) = 0
mprotect(0x79aecff000, 4096, PROT_READ) = 0
munmap(0x79aecf8000, 19285)             = 0
brk(NULL)                               = 0x57b1bd2000
brk(0x57b1bf3000)                       = 0x57b1bf3000
fstat(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(0x88, 0x2), ...}) = 0
write(1, "evilpan\n", 8evilpan
)                = 8
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

В сценариях, когда необходимо отслеживать системные вызовы, используйте strace даиндивидуальный очень подходит из инструментов, потому что для него основе PTRACE_SYSCALL отслеживать и на на основесередина перерыв из-за способа взять на себя управление всеми системными вызовами, даже если целевое использование не зависит libc в соответствии svc Также можно узнать. Однако очевидны и недостатки этого индивидуума. Из названия также видно, что он по своей сути программдана. основе ptrace Цель отслеживается, поэтому, если в коде другой стороны есть меры по борьбе с отладкой, вероятность ее обнаружения возрастает.

Также в Android В системе приложение Все процессы состоят из zygote fork вне, поэтому используйте strace Определить, когда отслеживать, труднее, а поскольку многие приложения имеют несколько процессов, требуется дополнительная фильтрация и очистка выходных данных.

подробнее о strace извыполнитьпринцип Можеткссылка: How does strace work?

jtrace

в первые дни strace Программа его пока не поддерживает рука64, поэтому Jonathan Levin Письмо Android Internal Написано в одной книге jtrace Этот инструмент предназначен для использования Android Отслеживание заявок. Хотя сейчас Google Также там AOSP Поддерживается в след, но jtrace Все же имеет свои уникальные преимущества:

  • поддерживать свойства системы из мониторинга доступа (setprop/getprop)
  • поддерживает входное событие из мониторинга (InputReader)
  • поддерживать Binder информацияизанализировать
  • поддерживать AIDL изанализировать
  • ……

Хотя jtrace да имеет закрытый исходный код, но предоставляет уникальные функции подключаемого модуля. Пользователь может использовать его для написания индивидуального подключаемого модуля (динамической библиотеки) на основе предоставляемого им интерфейса и использования. --plugin параметры или JTRACE_EXT_PATH Путь, указанный переменной среды, загружает плагин для реализации настраиваемой обработки анализа параметров системного вызова.

Хотя соотношение преимуществ strace Их гораздо больше, но ее недостатки не решены, jtrace Сама еще дана основе PTRACE_SYSCALL Выполняет отслеживание системы и поэтому легко обнаруживается средствами защиты от отладки приложений.

Подробности см.: http://newandroidbook.com/tools/jtrace.html

Frida

frida да На данный момент это самый известный в мире набор инструментов для динамического отслеживания. (Instrumentation),поддерживатьиспользовать js Скрипт для динамического отслеживания целевого приложения. Я думаю, читателям будет интересно frida Он не новичок в этом, поэтому я не буду здесь рассказывать об этом слишком подробно. Нет сомнений в том, что его функции богаты, но есть и некоторые недостатки, такие как:

  • frida-gum на основе inline-hook Живая перекомпиляция кода идентификации цели (JIT), которая более навязчива к самому приложению;
  • frida-inject необходимо получить образование от ptrace Внедрите и загрузите целевое приложение в первый раз агент имеет более короткое окно внедрения, что может быть обнаружено антиотладочными приложениями;
  • frida В настоящее время нет системы подтверждения уровня событий отслеживания, хотя frida-stalker Это можно сделать на уровне сборки, но накладные расходы слишком велики;
  • frida Оно слишком известно, поэтому на него нацелено много людей. frida из обнаружения функций;
  • ……

сродни Instrumentation Также есть инструменты QDBI,hookzz и т. д.

другой

Помимо упомянутых выше инструментов,,Существует также множество других инструментов для динамичного мониторинга.,например ltrace、gdb и т. д. Но ни один из этих инструментов не отвечает моим потребностям в полной мере. Если мы хотим, чтобы лошадь бегала быстро (низко над головой) и не ела траву (без вторжения), то мы можем сосредоточиться только на ядре.

Kernel Tracing 101

Если целью дадля является реализация мониторинга системных вызовов и некоторые параметры системных вызовов изменяются (например, IO Redirect), затем возникает интуитивная идея изменить исходный код Yadro, в настоящее время мы заинтересованы в том, чтобы из входа в систему вставить свой собственный код для достижения определенных функций. Но это очень неэффективно. Во-первых, нам нужно добавить код в различные функции, связанные с системными вызовами середина. Введение слишком большого количества модификаций затруднит обновление Ядро и объединение исходных материалов, во-вторых, нам нужно перекомпилировать Ядро каждый раз, когда мы вносим изменения. И соответствующее из. AOSP код (потому что ядро boot.img (подробнее см. ниже), а затем записать его в мобильный телефон или симулятор, процесс слишком сложен.

Еще одна уникальная идея, представленная Кодексом существования Ядро середина одноразового использования. батут, а затем существование впоследствии увеличивается и уменьшается системный вызов мониторинга входа через модуль Ядро из метода внесения изменений. Это кажется несколько более разумным, но на самом деле у Ядросередина уже есть много сродни Планов. Диптихи, это просто изобретение велосипеда. Это не только неэффективно, но и может быть введено в любой момент. kernel panic。

общий вид

Итак, что же есть у Ядросередина? Диптихи? На самом деле это непростой вопрос. Мы слышали об этом в ходе повседневной эксплуатации и технического обслуживания. kprobe、jprobe、uprobe、eBPF、tracefs、systemtab、perf,...Какие между ними отношения?,Какая польза от каждого?

Вот рекомендуемая статья: Linux tracing systems & how they fit together,Согласно его серединаизовому введению,Эти Ядро План Диптихи/инструменты можно разделить на три категории:

  1. данные: Классификация на основе данных мониторинга из источника
  2. Коллекция: Разделена в соответствии с исходным интерфейсом обратного вызова событий, предоставленным Ядро для состояния пользователя из
  3. внешний интерфейс: Получайте и анализируйте данные мониторинга событий. Инструмент пользователя.

trace

Эти решения для мониторинга будут кратко представлены позже.

kprobe

Проще говоря, kprobe может реализовать динамическое внедрение ядра, вставлять код отслеживания в любую инструкцию на основе метода прерывания и получать обратные вызовы через pre_handler/post_handler/fault_handler.

использовать

ссылка Linux в исходном коде samples/kprobes/kprobe_example.c,одининдивидуальный Простойиз kprobe Модуль ядра реализован следующим образом:

Язык кода:javascript
копировать
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>

#define MAX_SYMBOL_LEN  64
static char symbol[MAX_SYMBOL_LEN] = "_do_fork";
module_param_string(symbol, symbol, sizeof(symbol), 0644);

/* For each probe you need to allocate a kprobe structure */
static struct kprobe kp = {
    .symbol_name    = symbol,
};
/* kprobe pre_handler: called just before the probed instruction is executed */
static int handler_pre(struct kprobe *p, struct pt_regs *regs)
{
    pr_info("<%s> pre_handler: p->addr = 0x%p, pc = 0x%lx\n", p->symbol_name, p->addr, (long)regs->pc);
    /* A dump_stack() here will give a stack backtrace */
    return 0;
}
/* kprobe post_handler: called after the probed instruction is executed */
static void handler_post(struct kprobe *p, struct pt_regs *regs, unsigned long flags)
{
    pr_info("<%s> post_handler: p->addr = 0x%p\n", p->symbol_name, p->addr);
}
/*
 * fault_handler: this is called if an exception is generated for any
 * instruction within the pre- or post-handler, or when Kprobes
 * single-steps the probed instruction.
 */
static int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr)
{
    pr_info("fault_handler: p->addr = 0x%p, trap #%dn", p->addr, trapnr);
    /* Return 0 because we don't handle the fault. */
    return 0;
}

static int __init kprobe_init(void)
{
    int ret;
    kp.pre_handler = handler_pre;
    kp.post_handler = handler_post;
    kp.fault_handler = handler_fault;

    ret = register_kprobe(&kp);
    if (ret < 0) {
        pr_err("register_kprobe failed, returned %d\n", ret);
        return ret;
    }
    pr_info("Planted kprobe at %p\n", kp.addr);
    return 0;
}

static void __exit kprobe_exit(void)
{
    unregister_kprobe(&kp);
    pr_info("kprobe at %p unregistered\n", kp.addr);
}

module_init(kprobe_init)
module_exit(kprobe_exit)
MODULE_LICENSE("GPL");

После установки этого модуля ядра каждый раз, когда процесс в системе вызывает форк вызовет наш обработчик, таким образом, в dmesg середина выводит соответствующую информацию журнала. Примечательно изда, kprobe Модули зависят от конкретной архитектуры системы. pre_handler серединанаш адрес инструкции по печатииспользованияизда regs->pc,Да ARM64 из ситуации, если да X86 среду, соответствующую regs->ip,Может查看对应 arch из struct pt_regs выполнить.

принцип

kprobe рамка на основесерединаперерыввыполнить.когда kprobe После замены на команду «Зарегистрироваться» Ядро скопирует соответствующий адрес Воли из инструкции и заменит инструкцию для точки останова (например, X86 серединаиз int 3),Затем, когда Ядро будет выполнено по соответствующему адресу,серединаперерыв会被触发从而执行流程会被重定向到我们зарегистрироватьсяиз pre_handler Функция: когда исходная инструкция, соответствующая адресу из, будет выполнена, Ядро будет выполнено снова. post_handler (Может选),从而выполнитькомандный уровеньиз Ядродинамичныймонитор。То естьдаобъяснять,kprobe может не только отслеживать любую функцию с помощью символов из Ядро,Вы также можете отслеживать любые инструкции между функциями.

другой kprobe изродственникда kretprobe,Просто да следит за уровнем функции из Ядро,в соответствии спользовательзарегистрироватьсядоступен, когдаиз entry_handler и ret_handler Обратные вызовы выполняются при входе в функцию и перед возвратом. Конечно, это можно реализовать kprobe Также есть разница: не да проходит точку останова, а да проходит trampoline Реализация может немного сократить накладные расходы.

кто-то, возможно, слышал о Джей-проба, это рано Linux Ядроизизодининдивидуальный мониторинг реализован и был Kprobe заменять.

Дальнейшее чтение:

uprobe

uprobe Как следует из названия, относительно Ядро функция/адрес измонитора, в основном используется дляпользовательстатус функция/адрес мониторинга. Звучит так, будто «да» не «да», это немного волшебно. Как Ядро контролирует функцию состояния пользователя и звызов?

использовать

стоятьсуществоватьпользовательперспектива,Давайте сначала рассмотрим простой пример индивидуального,假设有этот么индивидуальныйодининдивидуальныйпользовательпрограмма:

Язык кода:javascript
копировать
// test.c
#include <stdio.h>
void foo() {
    printf("hello, uprobe!\n");
}
int main() {
    foo();
    return 0;
}

После компиляции,Посмотреть адрес определенного индивидуального символа из,Тогда скажите Ядро, что я хочу отслеживать этот индивидуальный адрес извызов:

Язык кода:javascript
копировать
$ gcc test.c -o test
$ readelf -s test | grep foo
    87: 0000000000000764    32 FUNC    GLOBAL DEFAULT   13 foo
$ echo 'p /root/test:0x764' > /sys/kernel/debug/tracing/uprobe_events
$ echo 1 > /sys/kernel/debug/tracing/events/uprobes/p_test_0x764/enable
$ echo 1 > /sys/kernel/debug/tracing/tracing_on

Затем запустите пользовательскую программу и проверьте, возвращается ли монитор Ядроиз:

Язык кода:javascript
копировать
$ ./test && ./test
hello, uprobe!
hello, uprobe!

$ cat /sys/kernel/debug/tracing/trace
# tracer: nop
#
# WARNING: FUNCTION TRACING IS CORRUPTED
#          MAY BE MISSING FUNCTION EVENTS
# entries-in-buffer/entries-written: 3/3   #P:8
#
#                              _-----=> irqs-off
#                             / _----=> need-resched
#                            | / _---=> hardirq/softirq
#                            || / _--=> preempt-depth
#                            ||| /     delay
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
#              | |       |   ||||       |         |
            test-7958  [006] .... 34213.780750: p_test_0x764: (0x6236218764)
            test-7966  [006] .... 34229.054039: p_test_0x764: (0x5f586cb764)

Конечно, не забудьте в конце отключить мониторинг:

Язык кода:javascript
копировать
$ echo 0 > /sys/kernel/debug/tracing/tracing_on
$ echo 0 > /sys/kernel/debug/tracing/events/uprobes/p_test_0x764/enable
$ echo > /sys/kernel/debug/tracing/uprobe_events

принцип

Выше из интерфейса дана основе debugfs (существоватьновееиз Ядросерединаиспользовать Tracefs), то есть читать и записывать файлы для достижения интерактивной реализации. uprobe монитор. который пишет uprobe_events пройдет серию вызовов ядра:

  • probes_write
  • create_trace_uprobe
  • kern_path: открыть целевой файл ELF;
  • alloc_trace_uprobe: выделить структуру uprobe;
  • Register_trace_uprobe: регистрация uprobe;
  • regiseter_uprobe_event: Воля probe Добавить в глобальный список середина и создать соответствующий из uprobe debugfs Оглавление, т.е. Примерсерединаиз выше p_test_0x764;

Когда уже зарегистрирован uprobe из ELF При запуске программы исполняемый файл будет иметь вид mmap Сопоставляется процессу с адресным пространством, и Ядро будет использовать виртуальное адресное пространство процесса середина, соответствующее из uprobe Адрес заменяется инструкцией точки останова. Когда целевая программа указывает на соответствующий из uprobe адрес, будет срабатывать точка останова, тем самым запуская uprobe изсередина прерывает процесс обработки (arch_uprobe_exception_notify),а потомсуществовать Ядросередина Распечатать Перепискаинформация。

и kprobe Аналогичным образом мы можем вызвать uprobe В это время текущая информация контекста выполнения извлекается в соответствии с соответствующим регистром, например, параметром функции ожидания. в то же время uprobe Есть и сродни родственники: uretprobe。использовать uprobe из Преимущества: мы можем получить много относительно абстрактной информации о состояниях Ядро, таких как bash середина readline Функция возврата, SSL_read/write из Открытое текстовое сообщение ждать.

Дальнейшее чтение:

tracepoints

tracepont да Ядросередина предоставляет облегченный план кода мониторинга,Может внедрить динамичныйвызовпользователь для обеспечения функций мониторинга.,Однако специалистам по сопровождению подсистемы необходимо при необходимости добавлять его в свой код.

использовать

tracepoint изиспользоватьи uprobe Аналогично, в основном на основе debugfs/tracefs из чтения и записи файлов для проверки Индивидуальная разница существует. uprobe использоватьизизпользователь определите собственную точку наблюдения (событие) и tracepoint использоватьизда Ядро код середина, заданный для точки наблюдения.

Посмотреть определение Ядро(илиDrive)середина из всех наблюдений:

Язык кода:javascript
копировать
$ cat /sys/kernel/debug/tracing/available_events
sctp:sctp_probe
sctp:sctp_probe_path
sde:sde_perf_uidle_status
....
random:random_read
random:urandom_read
...

Соответствующий каталог существующих событий содержит организацию структуры подсистемы и каталог точек наблюдения:

Язык кода:javascript
копировать
$ ls /sys/kernel/debug/tracing/events/random/
add_device_randomness  credit_entropy_bits  extract_entropy       get_random_bytes       mix_pool_bytes_nolock  urandom_read
add_disk_randomness    debit_entropy        extract_entropy_user  get_random_bytes_arch  push_to_pool           xfer_secondary_pool
add_input_randomness   enable               filter                mix_pool_bytes         random_read

$ ls /sys/kernel/debug/tracing/events/random/random_read/
enable  filter  format  id  trigger

к urandom дляпример,Это да Ядроиз функция генерации псевдослучайных чисел,Следуйте этому:

Язык кода:javascript
копировать
$ echo 1 > /sys/kernel/debug/tracing/events/random/urandom_read/enable
$ echo 1 > /sys/kernel/debug/tracing/tracing_on
$ head -c1 /dev/urandom 
$ cat /sys/kernel/debug/tracing/trace_pipe
            head-9949  [006] .... 101453.641087: urandom_read: got_bits 40 nonblocking_pool_entropy_left 0 input_entropy_left 2053

Чтосередина trace_pipe да вывод из конвейера, к блокировка из режима чтения, поэтому вам нужно сначала начать чтение, а затем получить /dev/urandom,然后就Можетк Посмотрите что-то вроде вышеизвыход。здесьвыходиз Форматдасуществовать Ядросерединаопределениеиз,Посмотрим ниже.

Конечно, не забудьте отключить трассировку в конце.

принцип

Согласно документации Ядро,Специалисты по сопровождению подсистемы могут добавлять точки трассировки, если они хотят добавить точки трассировки в свои функции.,Требуется два шага:

  1. Определить точки отслеживания
  2. использоватьточка отслеживания

Ядродля точки трассировки согласно предоставленному определению TRACE_EVENT Макро. пока urandom_read этотиндивидуальныйточка отслеживаниядляпример,Чтосуществовать Ядросерединаизопределениесуществовать include/trace/events/random.h:

Язык кода:javascript
копировать
#undef TRACE_SYSTEM
#define TRACE_SYSTEM random

TRACE_EVENT(random_read,
    TP_PROTO(int got_bits, int need_bits, int pool_left, int input_left),

    TP_ARGS(got_bits, need_bits, pool_left, input_left),

    TP_STRUCT__entry(
        __field(      int,  got_bits        )
        __field(      int,  need_bits       )
        __field(      int,  pool_left       )
        __field(      int,  input_left      )
    ),

    TP_fast_assign(
        __entry->got_bits   = got_bits;
        __entry->need_bits  = need_bits;
        __entry->pool_left  = pool_left;
        __entry->input_left = input_left;
    ),

    TP_printk("got_bits %d still_needed_bits %d "
          "blocking_pool_entropy_left %d input_entropy_left %d",
          __entry->got_bits, __entry->got_bits, __entry->pool_left,
          __entry->input_left)
);

Чтосередина:

  • random_read: trace Имя события не обязательно должно совпадать с именем функции, но обычно событие легко идентифицировать и оно связано с определенной ключевой функцией. Принадлежат random подсистема (состоящая из TRACE_SYSTEM определение макроса);
  • TP_PROTO: Прототип точки отслеживания определен, и можно понять тип входного параметра;
  • TP_ARGS: Определены параметры извызов «функции»;
  • TP_STRUCT__entry: используется для fast binary tracing,Можеткпониматьдляодининдивидуальныйместный C Структура определения;
  • TP_fast_assign: Вышеуказанное местное C Структура инициализации;
  • TP_printk: Похоже на: printk из Определение структурированного вывода, предыдущий раздел середина trace_pipe извыход结果就даздесьопределениеиз;

TRACE_EVENT Макрос не вставляет автоматически соответствующую функцию, а определяет индивидуальное имя для расширения. trace_urandom_read из функции требуется, чтобы разработчики Ядро выполняли существующий код середина самостоятельно вызовом. Вышеупомянутая точка отслеживания на самом деле дасуществовать. drivers/char/random.c Файлы середина перенесли вызов:

Язык кода:javascript
копировать
static ssize_t
urandom_read_nowarn(struct file *file, char __user *buf, size_t nbytes,
            loff_t *ppos)
{
    int ret;

    nbytes = min_t(size_t, nbytes, INT_MAX >> (ENTROPY_SHIFT + 3));
    ret = extract_crng_user(buf, nbytes);
    trace_urandom_read(8 * nbytes, 0, ENTROPY_BITS(&input_pool)); // <-- здесь
    return ret;
}

static ssize_t
urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
    unsigned long flags;
    static int maxwarn = 10;

    if (!crng_ready() && maxwarn > 0) {
        maxwarn--;
        if (__ratelimit(&urandom_warning))
            pr_notice("%s: uninitialized urandom read (%zd bytes read)\n",
                  current->comm, nbytes);
        spin_lock_irqsave(&primary_crng.lock, flags);
        crng_init_cnt = 0;
        spin_unlock_irqrestore(&primary_crng.lock, flags);
    }

    return urandom_read_nowarn(file, buf, nbytes, ppos);
}

Примечательно издафактически дасуществовать urandom_read_nowarn функция середина вместо да urandom_read функциясерединавызовиз,Таким образом, также можно видеть, что имя точки внедрения не связано напрямую с фактическим именем функции.,Просто его должно быть легко идентифицировать и найти.

Согласно приведенному выше введению, мы можем понять, что зонд точки трассировки:

  • Недостатки да должны быть определены самим разработчиком и добавлены в код Ядро середина,Немного инвазивный код;
  • Преимущества: четко определен формат параметров.,И существование различных версий Ядро середина относительно стабильно,kprobe Функция отслеживания из Ядро могла быть переименована или оптимизирована в версии под индивидуальным;

Кроме того, точка трассировки Кромесуществовать Ядрокодсерединапрямойопределение,Вы также можете добавить ксуществовать драйвер середина для динамичности.,используется Разработчикам драйверов удобно отлаживать и повторно использовать существующие файлы. debugfs окончательная архитектура。здесь有одининдивидуальный ПростойизПример пользовательской точки трассировки,Можетиспользуется для углубления пары tracepoint использоватьизпонимать。

Дальнейшее чтение:

USDT

USDT выражать Userland Statically Defined Tracing,Прямо сейчаспользовательстатическийопределение追踪 (Первыми уйдут товарищи из валютного круга). Возник из Sun из Dtrace инструмент, поэтому USDT probe также часто называют Dtrace probe。Можеткпониматьдля kernel tracepoint версия изпользовательского слоя, созданная самим разработчиком приложения, существует изпрограммсередина, добавлена ​​ключевая функция Настроить точку трассировки, немного Похоже на: printf Метод отладки (неправильный).

поддаодининдивидуальный Простойиз Пример:

Язык кода:javascript
копировать
#include "sys/sdt.h"
int main() {
  DTRACE_PROBE("hello_usdt", "enter");
  int reval = 0;
  DTRACE_PROBE1("hello_usdt", "exit", reval);
}

DTRACE_PROBEn да UDST (systemtap) Предоставьте определение точки отслеживания + вставьте вспомогательный макрос, n выразить параметр индивидуальный номер. После компиляции приведенного выше кода вы увидите, что введенный код USDT probe информация:

Язык кода:javascript
копировать
$ apt-get install systemtap-sdt-dev
$ gcc hello-usdt.c -o hello-usdt
$ readelf  -n ./hello-usdt
...
Displaying notes found in: .note.stapsdt
  Owner                Data size        Description
  stapsdt              0x0000002e       NT_STAPSDT (SystemTap probe descriptors)
    Provider: "hello_usdt"
    Name: "enter"
    Location: 0x0000000000001131, Base: 0x0000000000002004, Semaphore: 0x0000000000000000
    Arguments:
  stapsdt              0x00000038       NT_STAPSDT (SystemTap probe descriptors)
    Provider: "hello_usdt"
    Name: "exit"
    Location: 0x0000000000001139, Base: 0x0000000000002004, Semaphore: 0x0000000000000000
    Arguments: -4@-4(%rbp)

readelf -n выражатьвыход ELF середина NOTE Раздел информации.

существоватьиспользовать trace инструменты (например, BCC、SystemTap、dtrace) При отслеживании приложения процесс запуска середина изменит соответствующий адрес целевого процесса и заменит его на для. probe , когда существующее вызывает вызов, генерируется соответствующее событие для завершения сбора данных. обычно добавляют probe из Способда на основе uprobe Осознайте из.

использовать USDT Преимущества: Разработчики приложений могут самостоятельно определять точки отслеживания более высокого уровня, чтобы облегчить мониторинг и анализ на функциональном уровне, например node.js server Просто принеси это с собой USDT probe Баллы можно использовать для отслеживания HTTP запрос и выведите запрос из информации об ожидании пути. потому что USDT Требуется сотрудничество с разработчикомиспользовать,Не отвечает нашим первоначальным потребностям в обратном анализе,поэтому Я не буду представлять слишком много.。(Что实да Слишком ленив, чтобы соответствовать окружающей среде)

Дальнейшее чтение:

краткое содержание

Вышеупомянутое введение из четырех распространенных Ядро План мониторинга,В соответствии со статическим/динамическим типом.,Для обзора вы можете использовать следующую таблицу:

План мониторинга

статический

динамичный

Ядро

пользователь

Kprobes

Uprobes

Tracepoints

USDT

Если быть точным USDT Это не независимый источник данных мониторинга, поскольку его реализация по-прежнему зависит от uprobe,Но для симметрично и да положить существованиездесь,И каталог так выглядит лучше.

коллекция & внешний интерфейс

Выше мы представили несколько основных источников данных мониторинга в сегодняшней Ядросередине.,По сути, он может удовлетворить все потребности в мониторинге. Однако с точки зрения удобства использования,Только да реализует базовую архитектуру,использовать Естьиздана основа Ядро обеспечивает интерфейс системных вызовов/драйверов с издана основе debugfs/tracefs не очень дружелюбен к пользователю, поэтому существует множество инкапсуляций и повторных инкапсуляций внешнего мониторинга. интерфейса, в этом разделе представлено краткое введение в эти основные инструменты.

ftrace

ftrace да Ядросерединаиспользуется для реализует набор фреймворков для внутреннего отслеживания, что немного абстрактно, но на самом деле мы уже использовали его раньше, просто да tracefs серединаизиспользоватьизметод。

существоватьстарая версиясередина Ядросередина(4.1 До)использовать debugfs,обычно монтируемый в /sys/kernel/debug/tracing;существоватьновая версиясерединаиспользоватьнезависимыйиз трассировки, смонтированные в /sys/ядро/трассировка. Однако из соображений совместимости исходный путь по-прежнему сохраняется, поэтому мы называем его коллективно. tracefs。

ftrace обычно называется function tracer,Но помимо функции отслеживания,Также поддерживаются многие другие сведения о событиях из трека:

  • hwlat: отслеживание аппаратной задержки
  • irqsoff: серединапрерывание с задержкой отслеживания
  • preemptoff: Отслеживать в течение указанного интервала времени из CPU Преимущественное событие
  • пробуждение: отслеживайте пробуждение и задержку задачи с наивысшим приоритетом.
  • branch: Трек Ядросерединаиз likely/unlikely вызов
  • mmiotrace: отслеживать все аппаратные события чтения и записи определенного двоичного модуля.
  • ……

Android середина предоставляет индивидуальное краткое руководство по добавлению документа для Yadro ftrace поддерживать,Подробности см.: Using ftrace

perf

perf да Linux Дистрибутив середина предоставляет отдельную программу мониторинга производительности, основе Ядропоставлятьиз perf_event_open Системные вызовы для выборки процессов и получения информации. Линукс серединаиз perf Подсистемы могут реализовывать CPU Инструкция по отслеживанию и подсчету, к и сбору kprobe、uprobe и tracepoints из информации для достижения производительности системы из анализа.

существовать Android середина предоставляет простую версию индивидуального perf программа simpleperf,интерфейси perf похожий.

Хотя может контролировать системный вызов,Но недостаток в том, что да не может получить параметры системного вызова.,Тем более запрещено модифицировать Ядро кдинамичный. Поэтому он малопригоден для тестирования безопасности.,Больше дай APP Разработчик и производитель мобильных телефонов используют для анализа горячих точек производительности. Стоит упомянуть изда, перформанс В подсистеме было много лазеек, существуют Android История подъема власти в Ядро тоже оставила следы. :D

eBPF

eBPF для extended Berkeley Packet Filter из аббревиатуры БПФ Самое раннее даиспользуется для фильтрации пакетов из оптимизированной виртуальной машины имеет собственный набор инструкций, которые мы обычно используем tcpdump Внутри инструмента входные данные Воли из правил фильтра будут преобразованы в формат для BPF Инструкции, такие как:

Язык кода:javascript
копировать
$ tcpdump -i lo0 'src 1.2.3.4' -d
(000) ld       [0]
(001) jeq      #0x2000000       jt 2	jf 5
(002) ld       [16]
(003) jeq      #0x1020304       jt 4	jf 5
(004) ret      #262144
(005) ret      #0

Директива ассемблера выражать сообщает фильтру принимать только IP пакет и исходный код IP 地址для 1.2.3.4. Его набор инструкций серединаиз может кссссылку Linux Socket Filtering aka Berkeley Packet Filter (BPF)。eBPF существовать BPF В набор инструкций было внесено множество улучшений:

  • Количество регистров варьируется от 2 индивидуальный Увеличиватьдля 10 индивидуальный (R0 - R9);
  • Размер регистра варьируется от 32 Увеличение битадля 64 Кусочек;
  • условная директива jt/jf из целевой замены для jt/провал, просто да else По умолчанию ветки можно игнорировать;
  • добавлен bpf_call Командование К и Перепискавызовское соглашение,Сократить расходы в Ядровызовиз;
  • ……

Ядрожитьсуществоватьодининдивидуальный eBPF Интерпретатор также поддерживает JIT-компиляцию для увеличения скорости выполнения, но существуют важные индивидуальные ограничения. eBPF Программа не может повлиять на нормальное функционирование ядра Ядронагрузка eBPF программа前会对Что进行один次语义检查,Обеспечить безопасность кода,Основные ограничениядля:

  • Не может содержать циклы, это предотвращает eBPF программа чрезмерного потребления системных ресурсов (5.3 серединадобавленчастичный циклподдерживать);
  • Невозможно прыгнуть в обратном направлении,Что实То естьда Не может содержать циклы;
  • BPF программаиз Ограничение размера стекадля 512 байт;
  • ……

Все стратегии ограничения существуют в Ядроиз. eBPF verifier середина, в разных версиях есть небольшие различия. Стоит отметить, что в последние годы Linux Ядро много появлялся eBPF из уязвимостей, в основном да verifier из Ошибки логики проверки, многие из них все еще публикуются Pwn2Own,нодаиз-за разрешенийизпределсуществовать Android середина Обычные приложения не могут быть выполнены bpf(2) системные вызовы и поэтому не затрагиваются.

eBPF и perf_event Аналогично, фильтрация кода мониторинга, а также подключение и отключение реализованы с помощью метода виртуальной машины Ядро, который очень эффективен во многих сценариях. Для обычного пользователя в принципе напрямую не написано eBPF из команды для мониторинга, Хотя Ядро предоставляет несколько макросов для помощи eBPF программаиз написана, но на самом деле больше издаиспользовать верхнюю часть структуры инкапсуляции приходится на вызов, середина которого является самой известной из индивидуальных на да BCC。

BCC

BCC (BPF Compiler Collection) Содержит ряд инструментов, помогающих эксплуатационному и техническому персоналу писать код мониторинга, среди которых множество Python Привязка. Индивидуальный простой из Примерпрограмма выглядит следующим образом:

Язык кода:javascript
копировать
from bcc import BPF
prog="""
int kprobe__sys_clone(void *ctx) {
    bpf_trace_printk("Hello, World!\\n");
    return 0;
}
"""
BPF(text=prog).trace_print()

выполнить это python После кода, всякий раз, когда система серединаиз процесса вызова clone Системный вызов, программа напечатает “Hello World” Выводная информация. Вы можете видеть, что это очень полезно для динамического мониторинга кода. Например, мы можем передать. python Входящие параметры определяют интересующую систему печати и ее параметры без частой модификации кода.

eBPF Можно получить практически все источники данных мониторинга в Ядросередине, в том числе kprobes、uprobes、tracepoints Подожди, это официально repo середина дает множество примеров программы, например opensnoop Мониторинг строк открытия файлов для, execsnoop Мониторинг выполнения программ. Позже мы будем существовать Android Получите практическую демонстрацию системы, чтобы почувствовать ее мощь.

img-bcc

bpftrace

bpftrace да eBPF Фреймворк издругой инкапсуляции верхнего уровня, и BCC Разное изда bpftrace Определите набор себя из DSL Язык сценариев, синтаксис (также) аналогичен awk,Это упрощает реализацию богатых функций непосредственно через командную строку.,Перехватило несколько официальных заявлений:

Язык кода:javascript
копировать
# Отслеживайте все открытые файлы в системе (открыть/открыть) и распечатывайте процесс открытия файла и путь к открытому файлу.
bpftrace -e 'tracepoint:syscalls:sys_enter_open { printf("%s %s\n", comm, str(args->filename)); }'

# Система статистики середина выполнение отдельных процессов из системных вызовов общее количество
bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }'

Чиновник также дал много .bt Сценарии можно изучать и писать с помощью их кодов.

Дальнейшее чтение:

SystemTap

SystemTap(stab) да Linux серединаиз-индивидуальный инструмент командной строки, который может выполнять структурированный вывод различной исходной информации мониторинга Ядро. В то же время я также осознал свой собственный набор DSL Скрипт, синтаксис аналогичен awk может реализовать быстрое программирование команд мониторинга системы.

использовать systemtap Необходимо включить исходный код Ядро, поскольку для требуется динамичная компиляция и загрузка модуля Ядро. существовать Android середина Еще не официальноизподдерживать,но有один些Открытый исходный код из пересадки systemtap

Дальнейшее чтение: Comparing SystemTap and bpftrace

другой

В дополнение к приведенному выше введению, эти,Существует также множество внешних интерфейсов мониторинга с открытым исходным кодом.,например LTTng、trace-cmdkernelsharkждать,Результаты мониторинга сохраняются, обрабатываются и визуализируются в структурированном виде.,Очень полезно для больших объемов данных. Из-за ограниченности места эти инструменты не будут представлены по одному.,И авторов не так уж и много.,В будущем будут проводиться дальнейшие исследования.

Android-порт

начальство面объяснять了Такмного,Ведь только да Linux Релизная версия живая, поэтому эти trace методсуществовать Android Будет ли это работать? Теоретически AOSP Код с открытым исходным кодом, и код с открытым исходным кодом. Просто скомпилируйте его. Но на практике мы столкнемся с несколькими трудностями:

  1. Многие инструменты требуют скомпилированного кода, BCC. Инструменты тоже нужны Python Беги, это дефолтное существование существует из Android средасередина不житьсуществовать;
  2. Оригинальный предварительно скомпилированный образ Ядро, предоставленный заводом, не поставляется с kprobe ждатьмонитор功能поддерживать,Необходимо изменить конфигурацию самостоятельно,Записать и скомпилировать Ядро;
  3. Linux Старая версия для eBPF изподдержка не идеальна, многие новые функции дасуществовать 5.x Оно было введено позже и Android из Linux Ядро относительно стары и должны быть cherry-pick Даже вручную backport;
  4. AOSP В новых версиях представлены GKI(Generic Kernel Image),Необходимо поддерживать совместимость интерфейса драйвера Ядро.,поэтому Ядрокод不能引入过много修改;
  5. ……

Так как наша основная цель — провести обратный анализ Android-приложений,Поэтому лучше всего запускать его в реальной машинной среде.,Поскольку для многих приложений недоступна поддержка среды x86, конечно, также доступен эмулятор ARM.,Однако при атаке и защите от существования может потребоваться дополнительное обнаружение и обход эмулятора.

авториспользоватьизда Google Pixel 5,использоватьдругой сотовый телефон из слов необходимо соответствующим образом настроить.

1. Debian over Android

Android Сама система не предназначена для разработки, поэтому только простые встроенные busybox(toybox) Инструменты, и некоторые программы, связанные с управлением пакетами, такие как pm/am/dumpsys/input ждать. Чтобы создать полноценную среду разработки на основе существующего, нам необходимо иметь возможность запускать существующий Android-середина. gcc/clang、python、Makefile ждать, индивидуальный интуитивный из идеи да через песочницу, способ ожидания существует выше обычного обычного из Linux распространение, например Ubuntu или Debian。

androdeb Просто эта индивидуальная идея является индивидуальной реализацией, ее суть дана. основе chroot существовать Android середина运行了одининдивидуальный Debian aarch64 зеркало, и можно пройти apt Инструмент управления пакетами ожидания необходим для установки цепочки инструментов компиляции, чтобы существующее можно было скомпилировать и запустить. bcc ждать Linux проект.

существовать Android беги дальше Debian Система из Примерследующее:

Running Debian on Android

Главное правильно смонтировать родной Android серединаиз картографирования, например procfs、devfs、debugfs ждать。

2. Кастомное ядро

решеносуществовать Android беги дальше инструменты разработки из После решения проблемы нам также нужен индивидуальный управляющийдинамичный отладчик из Ядро среды. существуют Большая часть официальных прошивок середина поставляется с из Ядровключением KPROBES изпод поддержка, а это значит, что мы сами компилируем и загружаем Ядро.

Для поддержки функции ожидания KPROBES, UPROBES, TRACEPOINTS вам необходимо существование Ядроиз конфигурации середина, чтобы добавить следующие параметры:

Отключите функции безопасности Ядроиз, включая отладку поддержки:

Язык кода:javascript
копировать
-d CONFIG_LTO \
-d CONFIG_LTO_CLANG \
-d CONFIG_CFI_CLANG \
-d CFI_PERMISSIVE \
-d CFI_CLANG \
-e CONFIG_IRQSOFF_TRACER \
-e CONFIG_PREEMPT_TRACER \
-e CONFIG_DEBUG_FS \
-e CONFIG_CHECKPOINT_RESTORE \
-d CONFIG_RANDOMIZE_BASE \

Включите поддержку eBPF:

Язык кода:javascript
копировать
-e CONFIG_BPF \
-e CONFIG_BPF_SYSCALL \
-e CONFIG_BPF_JIT \
-e CONFIG_HAVE_EBPF_JIT \
-e CONFIG_IKHEADERS \

Включите поддержку kprobes:

Язык кода:javascript
копировать
-e CONFIG_HAVE_KPROBES \
-e CONFIG_KPROBES \
-e CONFIG_KPROBE_EVENT \

Включите поддержку kretprobe:

Язык кода:javascript
копировать
-e CONFIG_KRETPROBES \
-e CONFIG_HAVE_KRETPROBES \
-d CONFIG_SHADOW_CALL_STACK \
-e CONFIG_ROP_PROTECTION_NONE \

Включите поддержку ftrace:

Язык кода:javascript
копировать
-e CONFIG_FTRACE_SYSCALLS \
-e CONFIG_FUNCTION_TRACER \
-e CONFIG_HAVE_DYNAMIC_FTRACE \
-e CONFIG_DYNAMIC_FTRACE \

Включить поддержку uprobes:

Язык кода:javascript
копировать
-e CONFIG_UPROBES \
-e CONFIG_UPROBE_EVENT \
-e CONFIG_BPF_EVENTS \

BCC рекомендует установить опцию из:

Язык кода:javascript
копировать
-e CONFIG_DEBUG_PREEMPT \
-e CONFIG_PREEMPTIRQ_EVENTS \
-d CONFIG_PROVE_LOCKING \
-d CONFIG_LOCKDEP

для Во избежание различных экологических проблем,Я предлагаю для среды компиляции лучше всего выбрать чистую английскую виртуальную машину.,илипрямойиспользовать Docker Зеркало, составленное согласно официальному руководству, см.: Building Kernels

Скомпилируйте Ядро common из зависимостей:

Язык кода:javascript
копировать
$ pkg --add-architecture i386
$ apt install git ccache automake flex lzop bison \
gperf build-essential zip curl zlib1g-dev zlib1g-dev:i386 \
g++-multilib python-networkx libxml2-utils bzip2 libbz2-dev \
libbz2-1.0 libghc-bzlib-dev squashfs-tools pngcrush \
schedtool dpkg-dev liblz4-tool make optipng maven libssl-dev \
pwgen libswitch-perl policycoreutils minicom libxml-sax-base-perl \
libxml-simple-perl bc libc6-dev-i386 lib32ncurses5-dev \
x11proto-core-dev libx11-dev lib32z-dev libgl1-mesa-dev xsltproc unzip

Дальнейшее чтение:

3. Трансплантация ядра

После того, как вы успешно скомпилируете и запустите Ядро, вы, вероятно, обнаружите некоторые инструменты анализа Ядро, такие как BCC На существованиеиспользовать возникают различные проблемы, которые обычно вызваны да Ядро версией из. потому что eBPF в настоящий моментсуществовать Ядросередина Также там Частые обновления,поэтому许много新из特性并没有Увеличивать到когда前Ядроначальство。

Например,существовать Pixel 5 последняя поддержка Ядрода 4.19 Версия,существоватьэтотиндивидуальный Версиясередина,bpf_probe_read_user (issue#3175) Функция еще не добавлена ​​в Ядро, поэтому используйте BCC вернется к bpf_probe_read_kernel,Это существование Ядро вызовет ошибки при непосредственном чтении пользовательского пространства из данных (например, параметров системного вызова).,Поэтому нам нужно идти вручную cherry-pick Переписка commit,Прямо сейчассуществовать Linux 5.5 серединадобавить виз 6ae08ae3dea2

BCC Список всех необходимых функций Ядро и их представленных версий можно найти по адресу: BCC/kernel-versions.md,Неполный список показан ниже:

img-commit

поэтомудля了减少Может能遇到из Проблемы совместимости,Попробуйте использовать последнюю версию из Ядро,Конечно, обычно производители поддерживают только более старую версию LTS.,Выполняйте только необходимые обновления безопасности,Если вы не будете осторожны при покупке машины, вам придется постоять за себя.

Практический тест

проходитьсуществоватьначальство述 Android Debian Окружение составлено хорошо BCC После этого мы сможем киспользовать Python писать Переписка Применить скрипт анализа отслеживания。один般дапроходить应用名去过滤系统вызов,нодасуществовать Android середина и индивидуальный специальный метод фильтрации для да через пользователя ID, т.к. для приложения да получается по динамичной установке UID Перейти на изоляцию в песочнице.

к Некоторые отдельные слои усиления являются вредоносными APK например, получить его после установки UID для u0_a142,Преобразовать в числада 10142,对Что进行 exec Мониторинг системных вызовов:

img-exec

Вы можете увидеть вызов целевого приложения ps、getprop、pm программа ожидания, используемая для обнаружения текущей системы adb Статус к и установленных из приложений, таких как их серединапасс pm path com.topjohnwu.magisk судить Magisk инструментда否житьсуществовать,поэтомужитьсуществовать root Проверьте строку для. Картинка выше середина pm вообще-то позвонил cmd программа для поиска, потому что для pm 本质начальство只даодининдивидуальный shell Скрипт:

Язык кода:javascript
копировать
$ cat `which pm`
#!/system/bin/sh
cmd package "$@"

использовать UID Фильтрация преимуществ позволяет отслеживать все fork издочерний процесс и внуковый процесс, это дана основе PID или Отслеживание имени процесса несравнимо. Кроме exec, мы также можем проследить другую функцию Ядро, например root При тестировании часто используются openat или доступ, как показано ниже:

img-su

на основе Ядроуровень Мониторинг,Сделать все защитные меры приложения по усилению/скрытию/встроенной сборке ожидания неэффективными.,И вы можете наблюдать это на ранней стадии запуска приложения.,Пусть приложению из всего, что вы делаете для существовать середина, нечего скрывать от наших глаз.

PS: еслисуществоватьиспользовать BCC изпроцесссерединанайден без фильтрации UID из этого варианта вам может потребоваться переключиться на последнюю версию release Версия или master Ветка, потому что для этого индивидуального варианта автор только недавно добавил из.

img-pr

:D

Дальнейшее чтение:

Подвести итог

Эта статья Подвести подвел итоги и проанализировал несколько основных из Планов Ядро мониторинга,Они обычноиспользуется для мониторинга производительности и отладки, но мы также можем использовать его для анализа безопасности и существования Android середина провела реальные наступательные и оборонительные испытания и добилась реальных боевых эффектов, превзошедших ожидания. Помимо мониторинга уровня Ядро, мы также можем основе uprobes Обеспечьте мониторинг любого адреса в приложении, например существующего SSL_read/write Получите все по адресу SSL шифрованиеизданные。Воспользуйтесь Ядропоставлятьиз丰富монитор原语,Мы можем реализовать мобильную песочницу уровня Ядро.,Комплексный мониторинг работы мобильных приложений,Вы также можете изменять параметры системы с помощью примитивов чтения и записи Ядро.,Это позволяет моделировать и формировать среду выполнения приложения.

boy illustration
Быстро изучите в одной статье — концепцию и технологию реализации NL2SQL для передачи данных с нулевыми затратами.
boy illustration
Как использовать SpringBoot для интеграции EasyExcel 3.x для реализации элегантных функций импорта и экспорта Excel?
boy illustration
Почему транзакция не вступает в силу, когда @Transactional добавляется в частный метод?
boy illustration
Знание создания образов Docker: подробное объяснение команды Dockerfile.
boy illustration
Псевдостатическая конфигурация ThinkPHP
boy illustration
Код изображения для загрузки апплета WeChat: последний доступный (код серверной части + код внешнего интерфейса)
boy illustration
Используйте растровое изображение Redis для реализации эффективной функции статистики регистрации пользователей.
boy illustration
[Nginx29] Обучение Nginx: буфер прокси-модуля (3) и обработка файлов cookie
boy illustration
[Весна] SpringBoot интегрирует ShardingSphere и реализует многопоточную вставку 10 000 фрагментов данных в пакетном режиме (выполнение операций с базой данных и таблицами).
boy illustration
SpringBoot обрабатывает форму данных формы для получения массива объектов
boy illustration
Nginx от новичка до новичка 01 - Установка Nginx через установку исходного кода
boy illustration
Проект flask развертывается на облачном сервере и получает доступ к серверной службе через доменное имя.
boy illustration
Порт запуска проекта Spring Boot часто занят, полное решение
boy illustration
Java вызывает стороннюю платформу для отправки мобильных текстовых сообщений
boy illustration
Практическое руководство по серверной части: как использовать Node.js для разработки интерфейса RESTful API (Node.js + Express + Sequelize + MySQL)
boy illustration
Введение в параметры конфигурации большого экрана мониторинга Grafana (2)
boy illustration
В статье «Научно-популярная статья» подробно объясняется протокол NTP: анализ точной синхронизации времени.
boy illustration
Пример разработки: серверная часть Java и интерфейсная часть vue реализуют функции комментариев и ответов.
boy illustration
Nodejs реализует сжатие и распаковку файлов/каталогов.
boy illustration
SpringBootИнтегрироватьEasyExcelСложно реализоватьExcelлистимпортировать&Функция экспорта
boy illustration
Настройка среды под Mac (используйте Brew для установки go и protoc)
boy illustration
Навыки разрешения конфликтов в Git
boy illustration
Распределенная система журналов: развертывание Plumelog и доступ к системе
boy illustration
Артефакт, который делает код элегантным и лаконичным: программирование на Java8 Stream
boy illustration
Spring Boot(06): Spring Boot в сочетании с MySQL создает минималистскую и эффективную систему управления данными.
boy illustration
Как использовать ArrayPool
boy illustration
Интегрируйте iText в Spring Boot для реализации замены контента на основе шаблонов PDF.
boy illustration
Redis реализует очередь задержки на основе zset
boy illustration
Получить текущий пакет jar. path_java получает файл jar.
boy illustration
Краткое обсуждение высокопроизводительного шлюза Apache ShenYu