攻防世界逆向刷题笔记(新手模式9-1?)
bad_python
看样子是pyc文件损坏了。利用工具打开,发现是MAGIC坏了。搜下也没有头绪。

攻防世界-难度1- bad_python - _rainyday - 博客园
python Magic Number对照表以及pyc修复方法 - iPlayForSG - 博客园
看WP才知道36已经提示了pyc版本了。参考第二个文章,除了魔法数字还有8字节的额外信息。
但是我填充之后还是bad magic,再看看WP咋说的。原来代表文件大小的地方还不能为0.也就是第12个字节。

我们只需要修复一下就可以了。 妈的,用FF也不行,看来必须中规中矩才行。用E5成功了。、

识别出是XTEA加密,写出解密即可。后期我这又出问题了,这一步就不搞了吧
ereere
左边没有main了,依据start必定会出现main函数,一个个点找到了疑似main的函数。

base64换表+RC4。思路同攻防世界RE_ereere_攻防世界ereere-CSDN博客
用cyberchef解决的

easyEZbaby_app
定位到关键代码。主要看checkpass和checkUsername函数

首先是username,密码是zhishixuebao的MD5,以2为步长取。结果是:7afc4fcefc616ebd

pass则是如下。长度显然是15位,注意算法要求是char数组=0,说明赋值等式右边值是0(也就是48)。写出Python代码即可。
a=''
for i in range(15):a+=chr(((255 - i) + 2) - 98-48)
print(a)

toddler_regs
导入pdb文件,放进IDA分析。
持续跟踪,首先看到stage1,要求参数必须是要求的值,只能动调修改这个参数。
但是看起来没啥用啊,看看stage2.
发现stage1的用处了,他会把黄框部分设置为23.我们直接找到这个对应的值即可。注意team是个字符串数组,我们导出来看看,直接在C里面运行吧。

第一个team输出了:0Int
第二个代码和上面一样,结果是:nTJnU
组合起来就是flag{0Int_1s_n1c3_but_nTJnU_is_we1rd}
上面显然是错误的,可能会遇到这个地方刚好是\0直接截断。保险的做法是先定义好数组大小(如char[512][10],再直接去掉&运行即可)
exp:

也可以动调做,我电脑不知为何运行不起来这个软件,只能静态分析了。
easyre-xctf
看题目简介估计有壳。是UPX原版壳,官方工具就可以脱壳了。
但并没有明显的算法,只在字符部分看到了疑似flag的后半段。双击这里有一个符号名part2。
动调看看有没有提示,拿拿数据。
在内存发现了疑似的部分

根据其地址定位到函数,这就是第一个flag。函数名字有个part1,对应着part2.两个16进制转换为字符后就是part1.

七分靠猜,这里有运气成分,正常来说估计得搜part1了。
CatFly(还没有写出来)
看主函数很复杂。慢慢来看吧。

运行出来是个这,输入的东西会在左下角显示。那么main函数有的部分就可以不看了。
看到一个提示:

要记住逃逸密码??
难道是迷宫,分析这部分,\x1Bxxx是终端转义啊,看着是打印图形用的。
百思不得姐,还是看看WP吧。
re学习(29)攻防世界-CatFly(复原反汇编)_攻防世界catfly-CSDN博客
粗略浏览下发现没有我想要的,不过突然想到可以给main函数拷贝到VC,删去已知功能的函数再仔细分析看看。
暂时跳过,下次再看。
IgniteMe
跟进到主函数。
首先str长度需要大于4.
先来一个循环把str循环复制给v7。后两个if判断意思是大写转小写,小写转大写。

最关键的在后院吗,str2我们已经知道了,这就是目标。byte我们也知道,目标就是求v7。接下来的sub_4013c0跟进一下。
是一个表达式,相当于v7^0x55+72.那就很明显了,写出对应exp:
str2='GONDPHyGjPEKruv{{pj]X@rF'
byte=[ 0x0D, 0x13, 0x17, 0x11, 0x02, 0x01, 0x20, 0x1D, 0x0C, 0x02, 0x19, 0x2F, 0x17, 0x2B, 0x24, 0x1F, 0x1E, 0x16, 0x09, 0x0F, 0x15, 0x27, 0x13, 0x26, 0x0A, 0x2F, 0x1E, 0x1A, 0x2D, 0x0C, 0x22, 0x04]
flag=''
#根据str2猜测长度是24
for i in range(24):flag+=chr(((byte[i]^ord(str2[i]))-72)^0x55)
print(flag)
print(flag.lower())
出来的flag都是大写,不要忘记两个if判断是大写转小写小写转大写,因此再次转为小写即可
BABYRE
main函数看着很简单

需要注意:在 C 语言中,(*judge)(s) 这种语法表示通过函数指针调用函数。在 C 语言中,函数名本质上是指向函数代码起始地址的指针。可以将这个地址存储在一个函数指针变量中,然后通过该变量调用函数。
也就是说这是一段自修改代码。judge是函数,需要解密这段judge。
先用AI生成(因为我不太会IDA python)一段解密的脚本在IDA运行,然后C--P加载为函数即可
import idautils
import idaapibase = 0x600b00# 处理182个字节(与原始代码一致,0到181共182次)
for i in range(182):# 读取原始字节original_byte = idaapi.get_byte(base + i)# 异或解密decrypted_byte = original_byte ^ 0xC# 写入解密后的字节idaapi.patch_byte(base + i, decrypted_byte)# 标记为数据(这一行删了就行)无用idaapi.create_data(base + i, FF_BYTE, 1, idaapi.BADADDR)print(f"已解密 {base:X} 开始的182个字节")
再次从main函数进入judge即可了。 直接点进去judge好像部分代码还是错误,重新从main进去就好了。
这个加密逻辑就很明显了。
a='fmcd\x7Fk7d;V`;np'
flag=''
for i in range(len(a)):flag+=chr(ord(a[i])^i)
print(flag)

parallel-comparator-200
这一题直接给了C代码。有点意思。
注意到代码的flag_len是20.
首先认识一个新函数


逐步分析,main函数调用了下图的highly_.....函数。

跟进此函数。根据is_ok的判断条件,着重关注此部分,说明result值是0.因为is_ok的条件为generated==just_a_string。

查找用到result的地方。注意到只有first_letter未知,user_string是我们的目标。


最后一行代码实际上经过上文知识点铺垫,调用了checking函数。
由于result==0,说明argument[0]+argument[1]严格相等于argument[2]。会循环20次这个checking函数(因为pthread_creat函数在for循环内部循环了20次)
0我们不知道,(起码知道是某个小写字母)2是目标,1知道了。而且2就等于1+0.但是这还不太够啊,看看还有没有其余条件,似乎没了。

先尝试写一个爆破脚本试试。这里要注意,一定要多生成几个flag,因为不同的frist_letter对应不同的flag,我们试着a~z都搞一遍。第一次没想到这样遍历。而且代码美观不如豆包写的,还得多写多练。
、注意{}是占位符,可以写任意的表达式。
a = [0, 9, -9, -1, 13, -13, -4, -11, -9, -1, -7, 6, -13, 13, 3, 9, -13, -11, 6, -7]# 尝试所有可能的基准值b (97-122)
for base in range(97, 123):flag = []valid = Truefor i in a:char_code = base + iif 32 <= char_code <= 126:flag.append(chr(char_code))else:valid = Falsebreak # 这个基准值无效if valid:print(f"基准值 {chr(base)} ({base}): {''.join(flag)}")
发现flag
![]()
很让我开心的是我找到了大致思路!哈哈哈哈哈。只是脚本功底还比较薄弱。
secret-galaxy-300
注意到程序是打印了类似于星球的东西。

但是观察函数发现其实并没有完全打印出来,a1这个数组的部分内容并没有完全用到,所以我打算动调拿一波数据看看。
动调看a1并没发现明显的字符串
攻防世界逆向高手题之secret-galaxy-300-CSDN博客
看了别人的wp,反思一下,还是思路错了,这时候可以结合题目的提示,隐藏的星系,确实发现一个没有被打印出来的星系,点击ctrl+x查看交叉引用:
(而且我说为啥有三个代码差不多的文件,原来对应不同平台)

其实这里就可以看出来这估计就是flag了,这里偷了个懒,使用了AI。
# 定义各个星系名称字符串
ngs_2366 = "NGS 2366"
andromeda = "Andromeda"
messier = "Messier"
sombrero = "Sombrero"
triangulum = "Triangulum"
dark_secret_gala = "DARK SECRET GALAXY"# 将各个星系名称转换为字符列表,方便按索引取值
galaxy_strings = {"ngs_2366": list(ngs_2366),"andromeda": list(andromeda),"messier": list(messier),"sombrero": list(sombrero),"triangulum": list(triangulum),"dark_secret_gala": list(dark_secret_gala)
}def build_result_string():"""构建结果字符串"""result_chars = [galaxy_strings["andromeda"][8],galaxy_strings["triangulum"][7],galaxy_strings["messier"][4],galaxy_strings["andromeda"][6],galaxy_strings["andromeda"][1],galaxy_strings["messier"][2],'_',galaxy_strings["andromeda"][8],galaxy_strings["andromeda"][3],galaxy_strings["sombrero"][5],'_',galaxy_strings["andromeda"][8],galaxy_strings["andromeda"][3],galaxy_strings["andromeda"][4],galaxy_strings["triangulum"][6],galaxy_strings["triangulum"][4],galaxy_strings["andromeda"][2],'_',galaxy_strings["triangulum"][6],galaxy_strings["messier"][3]]return ''.join(result_chars)# 直接构建并打印结果字符串
print("构建的结果字符串:", build_result_string())
其实直接动调很快


simple-check-100
打开也是三个文件,有了前面的经验,这里面的代码一定是一样的
不如直接打开exe,动调起也方便
怀疑这部分的result就是最终的flag。

为了便于调试分析,我想使用动调的方法来做这道题。目前有两个思路,一个是直接改汇编代码,让这个条件强制为真,另一个是利用check_key来找v8的值,但是很遗憾看代码这个是v7地址对应的数组,估计不方便寻找和爆破。方便起见,先直接改汇编代码看看。
好吧,这种思路看着不太行的样子。OD出来的是乱码。估计是GBK编码不可以处理,这个估计不是GBK编码,

需要注意用X32得用管理员模式,刚才我patch了估计就是没管理员模式,他不认,IDA动调的patch估计没有静态的好使,patch了还是说wrong.
参考了攻防世界-simple-check-100_攻防世界 simple-check-100-CSDN博客看来这种动调还是找专业的调试器吧
我看人家都是用GDB动调的。linux估计不乱码。
新学的调试指令:set $eax=1
这里需要注意在这里改:,估计箭头跑到这里意思就是这个指令执行完毕了已经。
![]()
果不其然出来了flag。
接下来试试静态分析

注意参数本来是字符,搞成了int,因此本来一字节,导致合并为4字节。
还要注意这是一个嵌套for循环。
这借鉴了攻防世界 simple-check-100(非常好的一篇wp,日后还得多多观看,受益匪浅)-CSDN博客
#include <stdio.h>
int main(int argc, char *argv[])
{unsigned char flag_data[] = {220, 23, 191, 91, 212, 10, 210, 27, 125, 218,167, 149, 181, 50, 16, 246, 28, 101, 83, 83,103, 186, 234, 110, 120, 34, 114, 211};char v7[] = {84, -56, 126, -29, 100, -57, 22, -102, -51, 17,101, 50, 45, -29, -45, 67, -110, -87, -99, -46,-26, 109, 44, -45, -74, -67, -2, 106};unsigned int v2;unsigned char *v3;// v11 = -478230444;// v12 = -1709783196;// v13 = 845484493;// v14 = 1137959725;// v15 = -761419374;// v16 = -752063002;// v17 = -74;// v18 = -67;// v19 = -2;// v20 = 106;// 方法一:类比写for (int i = 0; i <= 6; ++i){v2 = ((v7[4 * i] & 0x000000FF) + ((v7[4 * i + 1] & 0x000000FF) << 8) + ((v7[4 * i + 2] & 0x000000FF) << 16) + ((v7[4 * i + 3] & 0x000000FF) << 24)) ^ 0xDEADBEEF;v3 = (unsigned char *)&v2;for (int j = 3; j >= 0; --j){printf("%c", *(v3 + j) ^ flag_data[4 * i + j]);}}// 方法二:按位异或,小端字节序,低位在低地址// for (int i = 0; i <= 6; ++i) {// printf("%c", v7[4 * i + 3] ^ 0xDE ^ flag_data[4 * i + 3]);// printf("%c", v7[4 * i + 2] ^ 0xAD ^ flag_data[4 * i + 2]);// printf("%c", v7[4 * i + 1] ^ 0xBE ^ flag_data[4 * i + 1]);// printf("%c", v7[4 * i] ^ 0xEF ^ flag_data[4 * i]);// }return 0;
}
代码分析:
v2的计算逻辑这行代码的核心是 将 4 个有符号字节组合成一个 32 位无符号整数,然后与
0xDEADBEEF进行异或运算。让我逐步拆解这个过程:1. 为什么需要
& 0x000000FF?
v7是一个 有符号字符数组(char v7[]),其中的负数(如-56)在内存中以补码形式存储(例如-56的补码是0xC8,即十进制的200)。问题:当将有符号数扩展为更大的类型(如
int)时,符号位会被保留。例如:
v7[1]的值是-56(二进制0xC8),如果直接转换为int,会变成0xFFFFFFC8(因为符号位扩展)。这会导致后续的位运算(如
<< 8)结果错误。解决方法:通过
& 0xFF将其截断为无符号字节:
-56 & 0xFF→0xC8(十进制200),确保高 24 位为0。2. 为什么要进行位移操作(
<< 8,<< 16,<< 24)?这是 小端序(Little Endian)字节组合 的过程:
假设有 4 个字节
b0, b1, b2, b3,对应的索引为4*i到4*i+3。在小端序中,低字节存放在低地址,高字节存放在高地址。因此,组合成 32 位整数的公式是:
plaintext
value = b0 + (b1 << 8) + (b2 << 16) + (b3 << 24)示例:
假设v7[4*i]到v7[4*i+3]的值为[84, -56, 126, -29](即[0x54, 0xC8, 0x7E, 0xE3]):
v7[4*i] & 0xFF→0x54(低字节)
v7[4*i+1] & 0xFF→0xC8
v7[4*i+2] & 0xFF→0x7E
v7[4*i+3] & 0xFF→0xE3(高字节)组合后的值:
0xE37EC854(注意字节顺序颠倒,符合小端序)。
主要是因为将字符指针弄成整数的,再加上端序转换,搞得很麻烦。
re1-100
开局这些都是反调试

函数功能与原理
管道概念:管道是一种进程间通信(IPC,Inter - Process Communication)机制,用于在具有亲缘关系(如父子进程)的进程间传递数据。它本质上是一个特殊的文件,遵循先进先出(FIFO)原则。
函数作用:在许多编程语言和系统(如 C、C++ 等基于 POSIX 标准的系统编程中),
pipe函数用于创建一个匿名管道。pipe函数通常接受一个包含两个文件描述符的数组作为参数(这里pParentWrite应该是数组首地址),其中一个文件描述符用于读取管道数据(通常是数组的第一个元素,记为fd[0]),另一个用于向管道写入数据(通常是数组的第二个元素,记为fd[1]- 成功时:返回 0。
- 失败时:返回 -1,并设置
errno来指示具体错误类型。
由此我们已经知道pparentread/pparentwrite都是什么意思。
这个代码大概意思就是判断输入的是不是完整。根据我的判断。
相关文章:
攻防世界逆向刷题笔记(新手模式9-1?)
bad_python 看样子是pyc文件损坏了。利用工具打开,发现是MAGIC坏了。搜下也没有头绪。 攻防世界-难度1- bad_python - _rainyday - 博客园 python Magic Number对照表以及pyc修复方法 - iPlayForSG - 博客园 看WP才知道36已经提示了pyc版本了。参考第二个文章&am…...
【golang】能否在遍历map的同时删除元素
Go 团队在设计时确实允许在迭代时删除当前元素,但是不建议直接使用 for k, v : range m 删除。对于单线程读写情况: 主要原因如下: 1. 迭代变量重用问题 Go 的 range 循环会重用迭代变量的内存地址。当你使用 for k, v : range m 时…...
制作一款打飞机游戏58:子弹模式组合
今天我们将继续深入探讨子弹模式系统,并在我们的模式编辑器上做一些收尾工作。 子弹模式系统的乐趣 首先,我想说,这个子弹模式系统真的非常有趣。看着屏幕上不断喷射的子弹,感觉真是太棒了! 合并修饰符 今天&#…...
使用新一代达梦管理工具SQLark,高效处理 JSON/XML 数据!
在应用开发领域,JSON/XML数据结构因其灵活性和通用性,成为开发者存储和交换数据的首选。然而,传统管理工具在处理这些半结构化数据时,往往存在可视化效果差、编辑效率低等问题,严重影响开发者的工作效率。 现在&#…...
Qt基础:数据容器类
数据容器类 1. QList1.1 使用创建和初始化添加和删除元素访问和修改元素查找和判断元素遍历列表排序和筛选与其他容器的转换 1.2 完整示例 1. QList 在Qt中,QList 是一个动态数组容器类,用于存储和管理相同类型的元素。它提供了快速随机访问、动态扩展和…...
Vue3监听对象数组属性变化方法
在Vue3中,监听对象数组中某个属性的变化可以通过以下几种方法实现: 方法一:深度监听整个数组并比较属性变化 使用 watch 函数并启用 deep: true,在回调中遍历比较新旧数组的特定属性。 javascript 复制 下载 import { ref, …...
深入了解PyTorch:起源、优势、发展与安装指南
深入了解PyTorch:起源、优势、发展与安装指南 目录 引言PyTorch简介PyTorch的优势 动态计算图直观易用的API强大的社区支持丰富的生态系统高性能与可扩展性 PyTorch的发展历程PyTorch的主要组件 Torch.TensorAutograd自动求导nn模块TorchvisionTorchText和TorchAu…...
DeepSeek智能对话助手项目
目录: 1、效果图2、实现代码3、温度和TopK的作用对比 1、效果图 2、实现代码 # import gradio as gr# def reverse_text(text): # return text[::-1]# demogr.Interface(fnreverse_text,inputs"text",outputs"text")# demo.launch(share&q…...
浅谈Mysql的MVCC机制(RC与RR隔离级别)
MVCC(Multi-Version Concurrency Control)多版本并发控制 说这个我们先来了解一下Mysql的隔离级别,因为MVCC和Mysql的隔离级别是有关的。 Mysql默认的隔离级别是RR(可重复读) 其他的隔离级别是读未提交(…...
uniapp-商城-72-shop(5-商品列表,购物车实现回顾)
我们通过前面的章节已经将数据添加到了购物车,但实际上购物车的处理还有很多东西需要完成。 我们看看如何将商品添加到购物车。 本文介绍了购物车功能的实现方式,重点讲解了如何将商品添加到购物车以及购物车状态管理的处理机制。主要内容包括:1. 通过Vuex管理购物车状态,包…...
【git】 pull + rebase 或 pull + merge什么区别?
在Git中,pull + rebase 和 pull + merge 是两种整合远程分支更新的方式,其核心区别在于如何处理提交历史。以下是详细对比: 核心区别 操作提交历史结构合并方式冲突处理适用场景pull + merge保留分支分叉和合并节点创建新的合并提交(Merge Commit)一次性解决所有冲突公共…...
1. 编程语言进化史与JavaScript
引言 作为一名开发者,理解编程语言的演进历史和核心特性是至关重要的。接下来将从编程语言的三个历史阶段入手,重点解析JavaScript的起源、特性及其与相关技术的关系,同时补充进制转换的基础知识,为初学者构建完整的知识体系。 一、编程语言的三大历史阶段 1. 机器语言(…...
Vue3 中 Axios 深度整合指南:从基础到高级实践引言
在现代前端开发中,与后端API的交互是构建动态应用的核心环节。Axios作为最流行的HTTP客户端之一,以其简洁的API和强大的功能在前端生态中占据重要地位。本文将全面探讨如何在Vue3项目中高效整合Axios,从基础配置到高级封装,从性能…...
MySQL#Select语句执行过程
服务端程序架构 MySQL 是典型的 C/S 架构,即 Client/Server 架构,服务器端程序mysqld。 Select语句执行过程 连接层 客户端和服务器端建立连接,客户端发送 SQL 至服务器端 SQL层 SQL语句处理 查询缓存: 缓存命中该SQL执行结果直…...
hbuilder中h5转为小程序提交发布审核
【注意】 [HBuilder] 11:59:15.179 此应用 DCloud appid 为 __UNI__9F9CC77 ,您不是这个应用的项目成员。1、联系这个应用的所有者,请求加入项目成员(https://dev.dcloud.net.cn "成员管理"-"添加项目成员")…...
文档注释:删还是不删
问题:代码中存在大量的文档注释,占用大量篇幅,一次难以看完整个文件,于是诞生了一个想法:删除所有文档注释,于是问了下 DeepWiki 文档注释对tree - sitter有影响吗?文档注释对Roocode大模型理解…...
【数据结构】单链表练习
1.链表的中间节点 https://leetcode.cn/problems/middle-of-the-linked-list/description/ 用快慢指针来解决 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ struct ListNode* middleNode(struct ListNode* he…...
JVM 性能优化终极指南:全版本兼容、参数公式与场景实战
一、引言 JVM 优化的核心难点在于版本兼容性与场景适配性。从 Java 8 到 Java 21,JVM 的内存模型、GC 策略和默认参数发生了巨大变化;从高并发 Web 到大数据批处理,不同业务场景对延迟、吞吐量的要求也截然不同。本文基于历史会话中用户关注…...
分布式爬虫监控架构设计
1. 监控架构核心组件 1.1 日志集中管理 设计目标:聚合所有节点的运行日志,支持实时查询与异常分析。 实现方式: 日志采集:各节点通过 logging 模块将日志发送至中央存储(如Elasticsearch或Redis)。 日志…...
MySQL的参数 innodb_force_recovery 详解
MySQL的参数 innodb_force_recovery 详解 innodb_force_recovery 是 InnoDB 存储引擎的一个重要参数,用于在数据库崩溃恢复时控制恢复行为的级别。这个参数主要在数据库无法正常启动时使用,可以帮助我们从损坏的数据库中恢复数据。 一 参数概述 参数名…...
学习vue3:跨组件通信(provide+inject)
目录 一,关于跨组件通信概述 二,跨组件传值 案例1(爷传孙) 三,跨组件传函数 案例2(爷传孙) 疑问:孙子传给爷爷是否可行呢? 一,关于跨组件通信概述 之前我们学习了父子组件的传…...
Alibaba Sentinel 入门教程:从理论到实战
文章目录 第一部分:理论篇1. Sentinel 简介2. Sentinel 核心原理2.1 资源与规则2.2 Sentinel 工作主流程2.3 核心类解析 3. Sentinel 功能支持与使用流程3.1 流量控制3.2 熔断降级3.3 系统自适应保护3.4 热点参数限流3.5 黑白名单控制3.6 使用流程 4. Sentinel 架构…...
2.3 TypeScript 非空断言操作符(后缀 !)详解
在 TypeScript 中,当你开启了严格的空值检查(strictNullChecks)后,变量如果可能是 null 或 undefined,就必须在使用前进行显式的判断。为了在某些场景下简化代码,TypeScript 提供了非空断言操作符ÿ…...
【菜狗work前端】小程序加if判断时不及时刷新 vs Web
零、前提: 实现input输入数字不大于10000(需要配合typenumber,maxlength5,这里没写) 一、探究代码: <input v-model"model1" input"changeModel1" placeholder"请输入拒收件…...
01 NLP的发展历程和挑战
1.人工智能行业介绍 ANI、AGI、ASI 以下是弱人工智能(ANI)、强人工智能(AGI)和超强人工智能(ASI)的对比表格: 类型定义当前状态弱人工智能(ANI)专注于特定任务&#x…...
TCP 三次握手:详解与原理
无图、长文警告!!!! 文章目录 一、引言二、TCP 三次握手的过程(一)第一次握手:SYN(同步序列号)(二)第二次握手:SYN-ACK(同…...
LabVIEW累加器标签通道
主要展示了 Accumulator Tag 通道的使用,通过三个并行运行的循环模拟不同数值的多个随机序列,分别以不同频率向累加器写入数值,右侧循环每秒读取累加器值,同时可切换查看每秒内每次事件的平均值,用于演示多线程数据交互…...
在 Unity 中,Start 方法直接设置 RectTransform 的位置,时出现问题,与预计位置不匹配。
改动之前的源代码:发现组件的位置,与设计的位置不一样,但是如果把这段代码,交给一个按钮按下回调,就不会出现问题。 void Start(){//初始化Text 行//读取配置文件;StaticDataObj obj Resources.Load<St…...
永磁同步电机控制算法--IP调节器
一、基本原理 在电机控制领域,现今普遍使用的是比例-积分(PI)控制器。然而,PI控制器有一些缺点,可能会在某些应用中产生一些问题,例如:一个非常快的响应,也同时具有过大的超调量。虽然设计PI控制器时,可以…...
Ubuntu 25.04 锁屏不能远程连接的解决方案
最近安装了一个 Ubuntu 25.04,偶然发现可以通过 windows 自带的 rdp 远程工具进行连接,内心狂喜。此外,还支持启动 VNC 协议,也就是默认支持了 rdp 和 vnc 连接。 看了以下,ubuntu 在用户级别下创建了一个远程桌面服务…...

