rust逆向初探

rust 逆向葵花宝典

rust逆向技巧

rust逆向三板斧:

[!NOTE]

  1. 快速定位关键函数 (真正的main函数):观察输出、输入,字符串搜索,断点等方法。
  2. 定位关键 加密区 :根据输入的flag,打硬件断点,快速捕获程序中对flag访问的位置(加密区)。
  3. 定位错误输出(附近一定有比较功能的程序):定位到比较位置后 提取出正确加密后的结果

秘诀1:一个函数在**被调试运行(F8)**之后,如果既有输出,又要我们输入,那么我们当前所在的函数肯定不是真正的main函数。

秘诀2:所以存在flag(无论加密前后)的内存区域,都要首先打上硬件读断点

秘诀3:在c语言层面,对临时变量、局部变量等的修改,在汇编层面一定会反映到对内存空间的修改上。

rust语言的传参、返回值

  1. 前6个参数分别使用di,si,dx,cx,r8,r9,返回值使用ax寄存器:

image-20241015175505969

go语言的传参、返回值

  1. 前6个参数,ax,bx,cx,di,si,r8 返回值 ax:

例题1:

题目:ciscn2024 rust_baby

定位关键函数 — main函数

  1. 先运行观察输出的错误字符串:

    image-20241012121043893

  2. 但是在ida中搜索不到,所以只能调试来快速定位关键输入、输出函数:

    现在入口函数打上断点:

    image-20241012121358925

    这个函数位置出现了输出,在这里下断点,后面步入进入该函数继续调试定位:

    image-20241012121508735

    调用了外面传入给rcx参数这个地址处的函数,该函数也有输出,继续步入:

    image-20241012121745727

    直到进入rcx这个函数,才捕获到了输出 where is your flag?: 的函数,且这里任然可以继续往下调试 ,而没有停止来让我们输入,说明sub_7FF6BC37C570这个函数大概率就是单纯的输出函数:

    image-20241012121918858

  3. 后面在定位到输入的位置,肯定在这个输出函数的后面,如果不在说明当前函数不是真正的main,还需要继续步入:

    单步直到这里,就停止下来,需要我们输入:

    image-20241012122307772

  4. 根据上面定位输入、输出,可以基本确定rcx这个函数就是真正的main函数。

定位flag的加密区

  1. 输入flag后,在flag的内存区打上硬件读断点,后面程序访问flag内存区时就会停止:

    这里打断点,然后F9继续执行:

    image-20241012123238249

    后续ida触发硬件读断点,这里大概率就是flag的加密区

    image-20241012123349249

    image-20241012123402149

    image-20241012123434434

  2. 分析伪代码、或者直接分析汇编代码,理清加密逻辑即可。这里将flag 8个字符(不够就用’E’填充),一组进入encode加密,出来后再异或0x33,最后放入到encode2_flag中:

    image-20241012123705580

    image-20241012123732682

    image-20241012123816937

  3. encode函数加密分析,将加密再输入可以看到他不是一个对称加密,可以直接排除纯异或的加密方式(对称加密):

    image-20241012124117025

    根据函数加密前后的结果,来开始推断加密方式(输入的字符串要有特点,会更容易看出来):

    image-20241012124407683

    输入 bbbbbbbb encode加密后 aabbccdd ,可以看出只是对字符进行简单的前后移位处理,可以多测试几组数据来中和判断。

    image-20241012124604842

    符合前面推断 ==> key_1 = [1,1,0,0,-1,-1,-2,-2] ,对字符的ASCII码进行加减操作。

继续定位下一个加密区:
  1. 输入的flag加密后在内存中的位置已经改变,所以前面的硬件断点后续没用,再在新的flag位置打上断点:

    image-20241012124956863

    继续执行F9,ida再次触发硬件断点,定位到下一个flag加密区:

    image-20241012125105018

    这里对加密后的flag进行访问,可能也是一个加密区

    image-20241012125132339

  2. 继续分析伪代码、或者汇编:

    这里只是将前面加密后的flag(encode2_flag),16个一组一共7轮,与一个key的数组进行异或,所以需要提取出这个key数组。首先确定这个key数组是不是静态的(与flag的长度、内容都无关),如果时静态的就能直接从内存中提取出来。

    这里可以通过输入不同的flag(内容不同、长度不同),来比较程序的key数组是否相同:

    先根据输入不同的flag,来比较第一轮的key:

    image-20241012130446758

    image-20241012130519046

    可以看到即使输入不同的flag,第一轮加密的key数组都是相同的,所以直接调试来从内存中提取出key数组,一共有7轮。

  3. 如果时动态的可以数组(与flag的输入相关),则另外分析。

继续定位下一个加密区:
  1. 同样再给第二次加密后的flag内存区打上硬件断点

    image-20241012131024191

    然后继续F9运行,再次触发硬件断点,所以这里也可能是一个加密区

    image-20241012131341030

  2. 分析伪代码、汇编代码:

    这个do_while循环中,并没有加密的成分,只是对flag做一个复值操作,换到另外一片内存区域:

    最后将两次加密后的flag全家转移到了另外一篇内存区域,并没有加密操作,所以这里不是加密区 ,但是还要在这里下一个硬件断点,因为保不准后面可以使用这片区域的flag再进行加密操作。

    image-20241012131558560

  3. 上面断点后继续执行F9,这里又触发ida的额硬件断点:

    image-20241012131801949

  4. 继续分析这里的伪代码、或者汇编代码,可以发现是base64加密,加密的表如下:

    image-20241012132010867

  5. base64加密完成后,又换了一个内存区域来存储:

    image-20241012132209388

    继续打上硬件断点后运行 F9,但是这次触发硬件断点也没有加密操作 和 内存区转换的操作,应该是单纯的检查而已:

    image-20241012132319916

  6. 最后在 base64加密后的内存区域 下断点,其他的断点都删除掉:

    然后在这里又触发了硬件断点:

    image-20241012160207153

    仔细观察可以发现这是一个比较的区域,后面的 错误输出也紧挨比较区 ,这里比较,输入的flag加密后 和 正确的flag加密后的结果:

    image-20241012160408543

    image-20241012160441695

解密

  1. 最后根据分析的加密,和提取出来的数据,逆向出flag:

    res = "igdydo19TVE13ogW1AT5DgjPzHwPDQle1X7kS8TzHK8S5KCu9mnJ0uCnAQ4aV3CSYUl6QycpibWSLmqm2y/GqW6PNJBZ/C2RZuu+DfQFCxvLGHT5goG8BNl1ji2XB3x9GMg9T8Clatc="# 分组异或
    key = [0xDC, 0x5F, 0x20, 0x22, 0xC2, 0x79, 0x19, 0x56, 0x35, 0xDA, 0x8B, 0x47, 0xD3, 0x19, 0xFC, 0x55,0x14, 0xCD, 0xD2, 0x7B, 0x58, 0x59, 0x09, 0x42, 0xDE, 0x2C, 0xB4, 0x48, 0xD9, 0xF2, 0x1B, 0xA9,0x40, 0xE1, 0xA6, 0xFB, 0xFF, 0x38, 0xC1, 0xD5, 0xE2, 0xE8, 0x77, 0x78, 0x6F, 0x22, 0x04, 0xE6,0x16, 0x3E, 0x0C, 0x35, 0x52, 0x5C, 0xFD, 0xC1, 0xE5, 0x59, 0x1C, 0xD0, 0xAE, 0x5A, 0xB2, 0xDD,0x19, 0xF8, 0x42, 0xE6, 0x2C, 0x89, 0x59, 0xE5, 0x11, 0x9C, 0xC8, 0x7B, 0x81, 0x70, 0x7F, 0x6F,0xBC, 0x6F, 0x02, 0x8F, 0xF7, 0xF4, 0xC8, 0x70, 0xAE, 0x02, 0xF8, 0x5B, 0xE2, 0x72, 0x08, 0x09,0x6F, 0xBF, 0x4B, 0x39, 0xB5, 0xD0, 0x1E, 0xA3, 0x23, 0xAB, 0x9B, 0x43, 0xB1, 0x15, 0xD7, 0xBE]table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"# base64解码后
    flag = [0x8a,0x07,0x72,0x76,0x8d,0x7d,0x4d,0x51,0x35,0xde,0x88,0x16,0xd4,0x04,0xf9,
    0x0e,0x08,0xcf,0xcc,0x7c,0x0f,0x0d,0x09,0x5e,0xd5,0x7e,0xe4,0x4b,0xc4,0xf3,0x1c,0xaf,
    0x12,0xe4,0xa0,0xae,0xf6,0x69,0xc9,0xd2,0xe0,0xa7,0x01,0x0e,0x1a,0x57,0x70,0x92,0x61,
    0x49,0x7a,0x43,0x27,0x29,0x89,0xb5,0x92,0x2e,0x6a,0xa6,0xdb,0x2f,0xc6,0xa9,0x6e,0x8f,
    0x34,0x90,0x59,0xfc,0x2d,0x91,0x66,0xeb,0xbe,0x0d,0xf4,0x05,0x0b,0x1b,0xcb,0x18,0x74,
    0xf9,0x82,0x81,0xbc,0x04,0xd9,0x75,0x8e,0x2d,0x97,0x07,0x7c,0x7d,0x18,0xc8,0x3d,0x4f,0xc0,0xa5,0x6a,0xd7]flag_1 = []# key异或
    for i in range(len(flag)):flag_1.append((flag[i] ^ key[i%len(key)]))
    print(flag_1)
    print()
    key_1 = [1,1,0,0,-1,-1,-2,-2]
    for i in range(len(flag)):print(chr((flag_1[i] ^ 0x33) + key_1[i%8]),end="")# flag{6e2480b3-4f02-4cf1-9bc0-123b75f9a922}
    

例题2:

题目: [羊城杯 2024]sedRust_happyVm | NSSCTF

  1. 根据输出的字符串快速定位到关键函数:

    image-20241013204747456

  2. 先给flag在内存打上硬件断点:

    image-20241013205152963

    F9块定位到访问flag的位置,开始会停在这里:

    image-20241013205451817

    分析汇编,多次尝试输入flag,以及根据下面对flag的检查,可以初步判断下面这部分程序的作用值检查flag是否合法,flag的头是否为 "DSACTF" 还有flag的长度是否为0x28

    image-20241013210611062

    image-20241013210708477

    输入 DASCTF{aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} 即可绕过这部分检查,继续给flag多上几个断点:

    image-20241013211411015

    继续F9 运行断在这里:

    image-20241013211635001

    分析汇编、结合内存,可以看到这里将flag的{}中的内容取出 换到了另外一个内存空间,原来的flag空间被释放掉,给新的内粗上断点:

    image-20241013211757795

    F9后程序停在这里,:

    image-20241013211931212

    分析汇编、观察内存后不难发现这是一个base64编码(没有编码表),下面这段程序就是做类似的base64编码,3个字符一组 8 * 3 = 6 * 4 :

    image-20241013212040496

    在另外一个内存空间存放base64编码的结果,仍然在这里下断点:

    image-20241013212232187

    程序后续停在这里:

    image-20241013212400781

  3. 看这里的整体框架不难发现应该是又对base64编码后的flag(base_flag)开始了加密处理 (下面每一个小框框都是类似的处理流程),后续对vm虚拟机位置的部分开始分析:

    image-20241013212440485

    根据断点位置,观察他是如何拿出base_flag的数据,放在了哪里。分析汇编观察寄存器的变化,不难发现他将base_flag两个一组取出,随后移位、相加、与,最后将取出的base_flag数据 与 程序本身的常数 0x0B1000018结合在一起,传入了vmp函数 进行加密:

    image-20241013212615799

    仔细观察汇编、以及寄存器,不难发现vmp函数是没有任何返回值,那最后要如何判定flag是正确与否呢。

  4. 这里先快速定位到输出flag 正确的位置:

    image-20241013213011486

    可以看到上面只有唯一一个位置能跳转到这里,暂时找过去观察。可以看到这里在最后一次加密后将一个内存区域与 0 做比较,如果为0则跳转到上面位置 输出You Get FLAG!

    image-20241013213103977

    所以在vmp函数中,应该是存在比较工作,在比较后会根据flag的正确与否来设置 内存区域[rsp+0C88h+check]的值,

    而且在所以vmp函数处理完成后,只有这一个位置对改内存区域进行了比较。所以前面任意一次vmp函数,对base_flag数据处理的结果都会影响改内存区域(他是唯一判断flag正确的条件)。

  5. 先看一眼vmp函数,根本一眼看不到头,狗都不看:

    image-20241013213812549

    这里根据上面的内存区域来反推,定位到在vmp函数中 flag正确与否的判断位置

    先给内存下一个硬件断点:

    image-20241013214018447

    F9快速定位到修改该内存的空间:
    image-20241013214148732

    可以发现在这里唯一修改了 该内存空间,修改的 条件是a1[1048]为1

    image-20241013214249109

    在看一下哪里影响了 a1[1048] 的值,上面对a1的交叉引用可以看到只有这两个位置修改了a1[1048],一个加法操作,一个异或操作:

    image-20241013214435939

    所以这两个位置是判断 flag释放正确的关键,该处下断点 (别的位置是否有修改这该处内存区域的值,可以用硬件断点如何完全调试一遍vmp函数即可):

    image-20241013214702268

  6. 从新回去找进入vmp函数时 传入的base_flag数据,毕竟vmp函数可能要对base_flag进行加密:

    在进入vmp前,将base_flag 和 程序自带的立即数0xB1000018 一起放在了rdx寄存器中:

    image-20241013215109595

    步入vmp函数,观察第一次rdx寄存器被访问的位置(有可能base_flag数据会被转移、或者加密):

    这里可以看到将edx的数据置入了一片内存区域中:

    image-20241013215311618

    给该处打上硬件断点(注意第二、三个值才是base_flag中取出的,第一个0x18是程序的立即数),后续edx寄存器的值被修改,就只有该内存区域存在base_flag数据

    image-20241013220753108

    F9后断在这里(这里会在上面加法操作的位置停下,直接步过不用管,因为没对flag进行加密),将base_flag数据取出 给到 eax 和 ecx,然后置入内存空间:

    image-20241013220143568

    image-20241013220647346

    上面下断点,F9,这里将另外一个base_flag数据取出,置入内存中:

    image-20241013220813093

    继续F9,断在这里,虽然改掉了base_flag但这里并不是加密,或者判断flag是否正确:

    image-20241013221132246

    继续F9,断在这里:

    image-20241013221318939

    再F9,会断再之前那个加法位置,观察此时的寄存器和内存,都没有base_flag的参数,所以直接步过:

    image-20241014104308751

    继续F9,直到触发硬件断点(访问到了base_flag数据)。在这里访问到了这前置入内存的base_flag数据,并转移到了另外一个内存空间中,并将原来的数据清空:

    image-20241014104508129

    image-20241014104737096

    给转移的base_flag数据在内存上下断点,继续F9,再次断在加法操作位置,这里内存和寄存器上的值都不是base_flag数据,所以直接跳过:

    image-20241014104845454

    继续F9,这里将转移的base_flag数据取出,转移到另外一片内存中,继续下断点:

    image-20241014104934889

    image-20241014105028186

    F9,断在异或操作的位置,观察对应内存和寄存器上的值,此时寄存器eax在再次转移的内存上取出了base_flag数据,并与另外一个内存上的数据进行异或,所以这力可能是对base_flag的一次加密、或者比较

    image-20241014105128218

    image-20241014105347338

    此时的异或值为0,而base_flag数据为0x18,明显不想等,异或出来的结果肯定不为0,所以如果这个是比较操作的话,后续肯定会根据异或的结果(非0),来修改最终判定条件,观察异或完后的操作是否对最终判定条件 进行了修改,单步发现在异或结束后,直接退出了该函数,返回到了vmp,所以上面的异或操作是对flag的一次加密 ,加密结果放在了内存中。打上断点:

    image-20241014105755786

    F9,再次断在了异或操作上,继续用上次的方法来判定该次异或是否为比较操作,这次异或 ==> 取出了原先放入的base_flag数据,并与上次异或后的值再次异或:

    image-20241014105851938

    该次异或完成后断在了要修改判定条件的位置 ,说明上次异或操作时一个比较 ==> 第一次异或后加密的值 与 内存上的值比较,两者相等才符合条件:

    image-20241014110140860

    这里可以提取出第一次异或时内存上的数据,和第二次异或时al寄存器上的数据,两则异或来还原出第一个base_flag。

    两外,这位两个位置的断点,有时候ida会设置为Unresolved 也就是未解析的状态,这里的原因不清楚,即使在异或函数中从新打上断点,只有再运行一个汇编代码,该断点就又会变成Unresolved。这就只能再程序的断点处观察内存和寄存器的值了:

    image-20241014112033223

    第二个base_flag数据处理,继续F9:

    image-20241014113456862

    F9后再次断在异或位置,这里寄存器al上是base_flag数据,内存[rsi+418h]上是与之异或的值,异或加密完成后退出该异或函数:

    image-20241014113535217

    F9,再次停在异或位置,这次是内存上是上次异或的值 al寄存器上是与之比较的值 ,:

    image-20241014113654101

    异或完成后,判定结果是否为0,来修改最总的判定条件:

    image-20241014113933642

  7. 综上vmp对base_flag数据的处理 ==> 一次传入两个base_flag数据,分别安排值与之异或加密 、然后异或一个正确的值根据结果是否为0 来修改最终的判定条件,进而完成比较操作,两个异或的数组都能从内存、或者寄存器上提取出来。经过多次vmp函数将所以base_flag数据处理完成,最后查看最终的判定条件 == 0。

    要验证异或的值与flag是否有关,可以每次输入不同的flag,来比较每次的异或值是否相同。

  8. 最后提取出来的这两组异或值,相互异或还原base_flag,再对base_flag解码,还原出输入的flag:

    xor_key = [0,0x82,0x11,0x92,0xa8,0x39,0x82,0x28,0x9a,0x61,0x58,0x8B,0xa2,0x43,0x68,0x89,0x04,0x8F,0xB0,0x43,0x49,0x3A,0x18,0x39,0x72,0x0C,0xBA,0x76,0x98,0x13,0x8B,0x46,0x33,0x2B,0x25,0xA2,0x8B,0x27,0xB7,0x61,0x7C,0x3F,0x58,0x56]
    res =  [0x18,0xb1,0x09,0xA4,0xa6,0x2a,0x9e,0x1B,0x96,0x57,0x5d,0xAD,0xAE,0x75,0x65,0xAC,0x09,0x8C,0xA0,0x76,0x47,0x2C,0x10,0x01,0x7C,0x0F,0xBA,0x47,0x95,0x30,0x9B,0x74,0x3F,0x2D,0x2D,0x9A,0x87,0x31,0xBA,0x43,0x70,0x2C,0x4C,0x56]
    base = []
    for i in range(len(res)):base.append( xor_key[i] ^ res[i] )
    print(base)# 类似base解码 6bit ==> 8bit
    tmp = ""
    for i in range(len(base)):tmp += "{:0>6}".format(bin(base[i])[2:])
    print(len(tmp))for i in range(0,len(tmp),8):print(chr(int(tmp[i:i+8],2)),end="")
    # DASCTF{c669733af3ce4459b88016420b81cb15}
    

    image-20241014114701169

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/60902.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

macbook git 设置和远程克隆项目

step1: git安装 step2: git配置 step3: ssh配置 Git的基本操作(Mac版)_mac gitbash-CSDN博客

vue项目npm run serve出现【- Network: unavailable】(从排查到放弃)

1. 问题现象 环境: 系统:win11node:v16.20.2“vue”: “2.6.10” 执行npm run serve启动vue项目,期望: App running at:- Local: http://localhost:9528/ - Network: http://x.x.x.x:9528/实际: App runn…

同比缩放,64的倍数,最大值

目录 opencv实现 opencv实现,只有缩小 import globimport cv2def resize_image(image, max_area800 * 400):original_height, original_width image.shape[:2]max_area_found 0best_resized_image None# 确定最小缩放比例,避免过度缩小导致图像信息…

项目技术栈-解决方案-web3去中心化

web3去中心化 Web3 DApp区块链:钱包:智能合约:UI:ETH系开发技能树DeFi应用 去中心化金融P2P 去中心化网络参考Web3 DApp 区块链: 以以太坊(Ethereum)为主流,也包括Solana、Aptos等其他非EVM链。 区块链本身是软件,需要运行在一系列节点上,这些节点组成P2P网络或者半…

STM32 标准库函数 GPIO_SetBits、GPIO_ResetBits、GPIO_WriteBit、GPIO_Write 区别

GPIO_SetBits: 使用例: GPIO_SetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2);意思是将GPIOA1和GPIOA2设为高电平 GPIO_SetBits(GPIOA, 0x0003);意思也是将GPIOA1和GPIOA2设为高电平 实际上当选中GPIOA时,它会按位遍历,在哪一位有1说…

贝叶斯网络——基于概率的图模型(详解)

贝叶斯网络(Bayesian Network,简称BN)是一种基于概率图模型的表示方法,用于表示变量之间的依赖关系,并通过条件概率推断变量间的关系。它通过有向无环图(DAG)来描述变量之间的依赖关系&#xff…

[智能车摄像头是一种安装在汽车上用于辅助驾驶和提高安全性的重要设备]

智能车摄像头是一种安装在汽车上用于辅助驾驶和提高安全性的重要设备。它们通常包括几个不同类型,如前视摄像头、环视摄像头、行车记录仪等。这些摄像头的主要功能有: 前视摄像头(Forward Camera):用于提供驾驶员前方…

用WordPress需要学习哪些编程知识

要使用WordPress搭建和管理网站,您需要掌握一些基本的编程知识。以下是一些关键的技能和概念: 基本编程知识 – HTML:用于构建网页的结构。 – CSS:用于设计和布局网页。 – PHP:WordPress是基于PHP的,…

numpy中的transpose()和pytorch中的permute()

它们都用于重新排列张量的维度,但在实现细节和使用方式上有所不同 numpy.transpose numpy.transpose 函数用于重新排列数组的维度。它接受一个元组作为参数,表示新的维度顺序。 numpy.transpose(a, axesNone) a:输入的数组。 axes&#xff…

linux,一、部署LNMP环境二、配置动静分离三、地址重写四、编写systemd Unit文件

一、部署LNMP环境 二、配置动静分离 三、地址重写 四、编写systemd Unit文件一、部署LNMP环境 环境说明 主机名 IP地址 角色 server1(已存在) eth0:192.168.88.254/24 客户端 proxy(已存在) eth0:192.168.8…

组件间通信(组件间传递数据)

组件间通信(组件间传递数据) 在 Vue.js 中,组件间通信是开发者需要经常处理的任务,特别是在构建具有多层次组件的复杂应用时。根据组件之间的关系和数据流的复杂程度,可以采用不同的通信方式。以下是常用的几种组件间通信方式: …

使用Element UI实现前端分页,及el-table表格跨页选择数据,切换分页保留分页数据,限制多选数量

文章目录 一、前端分页1、模板部分 (\<template>)2、数据部分 (data)3、计算属性 (computed)4、方法 (methods) 二、跨页选择1、模板部分 (\<template>)2、数据部分 (data)3、方法 (methods) 三、限制数量1、模板部分 (\<template>)2、数据部分 (data)3、方法…

git常用命令+搭vscode使用

1.克隆远程代码 git clone http:xxx git clone ssh:xxx clone的url 中 https和 ssh是有区别的: git中SSH和HTTP连接有什么区别-CSDN博客 当然https拉下来的代码每次pull /push都需要验证一次自己的账户和密码,可以config进行配置不用每次手敲: 解决VScode中每次git pu…

我的docker随笔45:在龙芯平台安装docker

本文介绍在龙芯平台安装docker。 前言 2017年下半年开始接触docker时&#xff0c;那会李大锤刚刚会爬&#xff0c;而今年&#xff08;2024年&#xff09;下半年&#xff0c;李大锤已经是一个经常考得C并且经常和妹妹吵架的二年级学生了。这么多年就过去&#xff0c;docker一直…

GitLab 如何跨版本升级?

本分分享 GitLab 跨版本升级的一些注意事项。 众所周知&#xff0c;GitLab 的升级必须要严格遵循升级路径&#xff0c;否则就会出现问题&#xff0c;导致升级失败。因此&#xff0c;在 GitLab 升级之前需要做好两件事情&#xff1a; 当前版本的确认升级路径的确认 极狐GitLa…

网上商城系统设计与Spring Boot框架

3 系统分析 当用户确定开发一款程序时&#xff0c;是需要遵循下面的顺序进行工作&#xff0c;概括为&#xff1a;系统分析–>系统设计–>系统开发–>系统测试&#xff0c;无论这个过程是否有变更或者迭代&#xff0c;都是按照这样的顺序开展工作的。系统分析就是分析系…

hive alter table add columns 是否使用 cascade 的方案

结论 alter table xxx add columns 时加上 cascade 时&#xff0c;会把所有的分区都加上此字段。如果不加则只有新的分区会加上此字段&#xff0c;旧的分区没有此字段&#xff0c;即便数据文件里有对应的数据&#xff0c;也不能显示内容。 如果分区都是 insert overwrite 生成…

C#笔记(3)

好的OOP程序--->模块合理、结构清晰、程序规范、注释明确、运行流畅、维护容易、扩展方法。 OOP是学习各种编程的原则、方法、技巧、经验、模式、架构等。 所有面向对象的编程语言&#xff0c;都是把我们要处理的”数据“和”行为“封装到类中。 1、设计类 2、关联类 3…

LabVIEW 实现 find_nearest_neighbors 功能(二维平面上的最近邻查找)

1. 背景介绍 在数据分析和图像处理领域&#xff0c;经常需要查找给定点的最近邻居点。在LabVIEW中&#xff0c;计算二维平面上多个点之间的欧氏距离&#xff0c;并返回距离最近的几个点是一种常见操作。find_nearest_neighbors 函数用于实现这个功能。 2. 欧氏距离计算 在二维…

Python如何从HTML提取img标签下的src属性

目录 前提准备步骤1. 解析HTML内容2. 查找所有的img标签3. 提取src属性 完整代码 前提准备 在处理网页数据时&#xff0c;我们经常需要从HTML中提取特定的信息&#xff0c;比如图片的URL。 这通常通过获取img标签的src属性来实现。 在开始之前&#xff0c;你需要确保已经安装…