BUUCTF reverse wp 51 - 55
findKey

shift + f12 找到一个flag{}字符串, 定位到关键函数, F5无效, 大概率是有花指令, 读一下汇编


这里连续push两个byte_428C54很奇怪, nop掉下面那个, 再往上找到函数入口, p设置函数入口, 再F5

LRESULT __stdcall sub_401640(HWND hWndParent, UINT Msg, WPARAM wParam, LPARAM lParam)
{int v5; // eaxsize_t v6; // eaxDWORD v7; // eaxint v8; // eaxint v9; // eaxCHAR *v10; // [esp+0h] [ebp-44Ch]CHAR v11[256]; // [esp+54h] [ebp-3F8h] BYREFchar v12[7]; // [esp+154h] [ebp-2F8h] BYREF__int16 v13; // [esp+15Bh] [ebp-2F1h]char v14; // [esp+15Dh] [ebp-2EFh]char Str[253]; // [esp+160h] [ebp-2ECh] BYREF__int16 v16; // [esp+25Dh] [ebp-1EFh]char v17; // [esp+25Fh] [ebp-1EDh]CHAR v18[256]; // [esp+260h] [ebp-1ECh] BYREFCHAR String[4]; // [esp+360h] [ebp-ECh] BYREFint v20; // [esp+364h] [ebp-E8h]__int16 v21; // [esp+368h] [ebp-E4h]CHAR Text[32]; // [esp+36Ch] [ebp-E0h] BYREFstruct tagRECT Rect; // [esp+38Ch] [ebp-C0h] BYREFCHAR Buffer[100]; // [esp+39Ch] [ebp-B0h] BYREFHDC hdc; // [esp+400h] [ebp-4Ch]struct tagPAINTSTRUCT Paint; // [esp+404h] [ebp-48h] BYREFint v27; // [esp+444h] [ebp-8h]int v28; // [esp+448h] [ebp-4h]LoadStringA(hInstance, 0x6Au, Buffer, 100);if ( Msg > 0x111 ){if ( Msg == 517 ){if ( strlen((const char *)String1) > 6 )ExitProcess(0);if ( strlen((const char *)String1) ){memset(v18, 0, sizeof(v18));v6 = strlen((const char *)String1);memcpy(v18, String1, v6);v7 = strlen((const char *)String1);sub_40101E(String1, v7, v10);strcpy(Str, "0kk`d1a`55k222k2a776jbfgd`06cjjb");memset(&Str[33], 0, 0xDCu);v16 = 0;v17 = 0;strcpy(v12, "SS");*(_DWORD *)&v12[3] = 0;v13 = 0;v14 = 0;v8 = strlen(Str);sub_401005(v12, (int)Str, v8);if ( _strcmpi((const char *)String1, Str) ){SetWindowTextA(hWndParent, "flag{}");MessageBoxA(hWndParent, "Are you kidding me?", "^_^", 0);ExitProcess(0);}memcpy(v11, &unk_423030, 0x32u);v9 = strlen(v11);sub_401005(v18, (int)v11, v9);MessageBoxA(hWndParent, v11, 0, 0x32u);}++dword_428D54;}else{if ( Msg != 520 )return DefWindowProcA(hWndParent, Msg, wParam, lParam);if ( dword_428D54 == 16 ){strcpy(String, "ctf");v20 = 0;v21 = 0;SetWindowTextA(hWndParent, String);strcpy(Text, "Are you kidding me?");MessageBoxA(hWndParent, Text, Buffer, 0);}++dword_428D54;}}else{switch ( Msg ){case 0x111u:v28 = (unsigned __int16)wParam;v27 = HIWORD(wParam);if ( (unsigned __int16)wParam == 104 ){DialogBoxParamA(hInstance, (LPCSTR)0x67, hWndParent, (DLGPROC)DialogFunc, 0);}else{if ( (unsigned __int16)wParam != 105 )return DefWindowProcA(hWndParent, Msg, wParam, lParam);DestroyWindow(hWndParent);}break;case 2u:PostQuitMessage(0);break;case 0xFu:hdc = BeginPaint(hWndParent, &Paint);GetClientRect(hWndParent, &Rect);v5 = strlen(Buffer);DrawTextA(hdc, Buffer, v5, &Rect, 1u);EndPaint(hWndParent, &Paint);break;default:return DefWindowProcA(hWndParent, Msg, wParam, lParam);}}return 0;
}int __cdecl sub_4013A0(BYTE *pbData, DWORD dwDataLen, LPSTR lpString1)
{DWORD i; // [esp+4Ch] [ebp-24h]CHAR String2[4]; // [esp+50h] [ebp-20h] BYREFBYTE v6[16]; // [esp+54h] [ebp-1Ch] BYREFDWORD pdwDataLen; // [esp+64h] [ebp-Ch] BYREFHCRYPTHASH phHash; // [esp+68h] [ebp-8h] BYREFHCRYPTPROV phProv; // [esp+6Ch] [ebp-4h] BYREFif ( !CryptAcquireContextA(&phProv, 0, 0, 1u, 0xF0000000) )return 0;if ( CryptCreateHash(phProv, 0x8003u, 0, 0, &phHash) ){if ( CryptHashData(phHash, pbData, dwDataLen, 0) ){CryptGetHashParam(phHash, 2u, v6, &pdwDataLen, 0);*lpString1 = 0;for ( i = 0; i < pdwDataLen; ++i ){wsprintfA(String2, "%02X", v6[i]);lstrcatA(lpString1, String2);}CryptDestroyHash(phHash);CryptReleaseContext(phProv, 0);return 1;}else{CryptDestroyHash(phHash);CryptReleaseContext(phProv, 0);return 0;}}else{CryptReleaseContext(phProv, 0);return 0;}
}
发现string1会经过sub_4013A0中的hash处理, 查MSDN的文档
https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id?redirectedfrom=MSDN

猜测是经过md5处理, 返回的值与0kk`d1a`55k222k2a776jbfgd`06cjjb ^ SS的结果比较
s = '0kk`d1a`55k222k2a776jbfgd`06cjjb'
key = 'SS'md5val = ''
for i in range(len(s)):md5val += chr(ord(s[i]) ^ ord(key[i % 2]))print(md5val)
查MD5, 得到解密真正flag的key == 123321
unsigned int __cdecl sub_401590(LPCSTR lpString, int a2, unsigned int a3)
{unsigned int result; // eaxunsigned int i; // [esp+4Ch] [ebp-Ch]unsigned int v5; // [esp+54h] [ebp-4h]v5 = lstrlenA(lpString);for ( i = 0; ; ++i ){result = i;if ( i >= a3 )break;*(_BYTE *)(i + a2) ^= lpString[i % v5];}return result;
}
shift + e导出unk_423030数据, 写逆
enc = [87, 94, 82, 84, 73, 95, 1, 109, 105, 70, 2, 110, 95, 2, 108, 87, 91, 84, 76
]
key = "123321"
flag = ''for i in range(len(enc)):flag += chr(enc[i] ^ ord(key[i % 6]))print(flag)
firmware
$ file 51475f91-7b90-41dd-81a3-8b82df4f29d0.bin
51475f91-7b90-41dd-81a3-8b82df4f29d0.bin: firmware 941 v7 TP-LINK Technologies ver. 1.0, version 3.15.36, 4063744 bytes or less, at 0x200 772784 bytes , at 0x100000 2883584 bytes$ binwalk -e 51475f91-7b90-41dd-81a3-8b82df4f29d0.bin$ ls _51475f91-7b90-41dd-81a3-8b82df4f29d0.bin.extracted/
120200.squashfs 20400 20400.7z squashfs-root
包含一个squashfs文件系统镜像, 需要使用firmware-mod-kit工具包内的unsquashfs_all.sh解压文件系统镜像
需要在linux里编译, 而且安装过程也比较坑, 嫌麻烦的直接上kali
git clone https://github.com/mirror/firmware-mod-kit.git
sudo apt-get install build-essential zlib1g-dev libz1zma-dev python-magic
cd firmware-mod-kit/src
./configure && make
kali执行
sudo apt update
sudo apt upgrade
sudo apt install firmware-mod-kit
apt安装的软件, 可以用dpkg -L xxx显示安装路径, 然后用unsquashfs_all.sh解析文件系统
┌──(kali㉿kali)-[~/Desktop]
└─$ /opt/firmware-mod-kit/trunk/unsquashfs_all.sh 120200.squashfs
Attempting to extract SquashFS 4.X file system...Skipping squashfs-2.1-r2 (wrong version)...
Skipping squashfs-3.0 (wrong version)...
Skipping squashfs-3.0-lzma-damn-small-variant (wrong version)...
Skipping others/squashfs-2.0-nb4 (wrong version)...
Skipping others/squashfs-2.2-r2-7z (wrong version)...
Skipping others/squashfs-3.0-e2100 (wrong version)...
Skipping others/squashfs-3.2-r2 (wrong version)...
Skipping others/squashfs-3.2-r2-lzma (wrong version)...
Skipping others/squashfs-3.2-r2-lzma/squashfs3.2-r2/squashfs-tools (wrong version)...
Skipping others/squashfs-3.2-r2-hg612-lzma (wrong version)...
Skipping others/squashfs-3.2-r2-wnr1000 (wrong version)...
Skipping others/squashfs-3.2-r2-rtn12 (wrong version)...
Skipping others/squashfs-3.3 (wrong version)...
Skipping others/squashfs-3.3-lzma/squashfs3.3/squashfs-tools (wrong version)...
Skipping others/squashfs-3.3-grml-lzma/squashfs3.3/squashfs-tools (wrong version)...
Skipping others/squashfs-3.4-cisco (wrong version)...
Skipping others/squashfs-3.4-nb4 (wrong version)...Trying ./src/others/squashfs-4.2-official/unsquashfs... Parallel unsquashfs: Using 4 processorsTrying ./src/others/squashfs-4.2/unsquashfs... Parallel unsquashfs: Using 4 processorsTrying ./src/others/squashfs-4.0-lzma/unsquashfs-lzma... Parallel unsquashfs: Using 4 processors
480 inodes (523 blocks) to write[====================================================| ] 454/523 86%
created 341 files
created 39 directories
created 70 symlinks
created 0 devices
created 0 fifos
File system sucessfully extracted!
MKFS="./src/others/squashfs-4.0-lzma/mksquashfs-lzma"
提取出文件系统中的内容后, 把各个目录翻一遍, 找到backdoor文件

查壳发现UPX

直接 kali 脱壳
┌──(kali㉿kali)-[~/Desktop/squashfs-root/tmp]
└─$ upx -d backdoor Ultimate Packer for eXecutablesCopyright (C) 1996 - 2020
UPX 3.96 Markus Oberhumer, Laszlo Molnar & John Reiser Jan 23rd 2020File size Ratio Format Name-------------------- ------ ----------- -----------54907 <- 19508 35.53% linux/arm backdoorUnpacked 1 file.
拖进IDA
bool initConnection()
{char *v0; // r0char s[512]; // [sp+4h] [bp-208h] BYREFint v3; // [sp+204h] [bp-8h]memset(s, 0, sizeof(s));if ( mainCommSock ){close(mainCommSock);mainCommSock = 0;}if ( currentServer )++currentServer;elsecurrentServer = 0;strcpy(s, (&commServer)[currentServer]);v3 = 36667;if ( strchr(s, 58) ){v0 = strchr(s, 58);v3 = atoi(v0 + 1);*strchr(s, 58) = 0;}mainCommSock = socket(2, 1, 0);return connectTimeout(mainCommSock, s, v3, 30) == 0;
}.data:0001B108 E4 19 01 00 commServer DCD aEchoByethost51 ; DATA XREF: initConnection+8C↑o
.data:0001B108 ; .text:off_10C2C↑o
.data:0001B108 ; "echo.byethost51.com"
在initConnection函数中进行链接建立操作, 可以分析出端口和地址
import hashlibflag = hashlib.md5(b'echo.byethost51.com:36667')
print('flag{' + flag.hexdigest() + '}')
[网鼎杯 2020 青龙组]jocker

// positive sp value has been detected, the output may be wrong!
int __cdecl main(int argc, const char **argv, const char **envp)
{char Str[50]; // [esp+12h] [ebp-96h] BYREFchar Destination[80]; // [esp+44h] [ebp-64h] BYREFDWORD flOldProtect; // [esp+94h] [ebp-14h] BYREFsize_t v7; // [esp+98h] [ebp-10h]int i; // [esp+9Ch] [ebp-Ch]__main();puts("please input you flag:");if ( !VirtualProtect(encrypt, 0xC8u, 4u, &flOldProtect) )exit(1);scanf("%40s", Str);v7 = strlen(Str);if ( v7 != 24 ){puts("Wrong!");exit(0);}strcpy(Destination, Str);wrong(Str);omg(Str);for ( i = 0; i <= 186; ++i )*((_BYTE *)encrypt + i) ^= 0x41u;if ( encrypt(Destination) )finally(Destination);return 0;
}char *__cdecl wrong(char *a1)
{char *result; // eaxint i; // [esp+Ch] [ebp-4h]for ( i = 0; i <= 23; ++i ){result = &a1[i];if ( (i & 1) != 0 )a1[i] -= i;elsea1[i] ^= i;}return result;
}int __cdecl omg(char *str)
{int testval[24]; // [esp+18h] [ebp-80h] BYREFint i; // [esp+78h] [ebp-20h]int success; // [esp+7Ch] [ebp-1Ch]success = 1;qmemcpy(testval, &unk_4030C0, sizeof(testval));for ( i = 0; i <= 23; ++i ){if ( str[i] != testval[i] )success = 0;}if ( success == 1 )return puts("hahahaha_do_you_find_me?");elsereturn puts("wrong ~~ But seems a little program");
}
wrong和omg函数逻辑很简单, 测试的数组也是硬编码的, 不过逆回去之后会发现是假的flag, 所以关键处理逻辑就是encrypt函数了
main函数虽然SP不对, 但是IDA7.7可以直接F5, 大概看一下逻辑也能看懂, 只有encrypt函数不能反编译, 因为上面的for循环是做代码修改的, 可以IDAPython修改回去;
也可以动调然后dump出来

拿到dump得到exe, 拖进IDA分析encrypt
int __cdecl start(int a1)
{int v2[19]; // [esp+1Ch] [ebp-6Ch] BYREFint v3; // [esp+68h] [ebp-20h]int i; // [esp+6Ch] [ebp-1Ch]v3 = 1;qmemcpy(v2, &unk_403040, sizeof(v2));for ( i = 0; i <= 18; ++i ){if ( (char)(*(_BYTE *)(i + a1) ^ aHahahahaDoYouF[i]) != v2[i] ){puts("wrong ~");v3 = 0;exit(0);}}puts("come here");return v3;
}
就是和aHahahahaDoYouF数组进行xor, 直接REV
#include <iostream>
#include <string>
using namespace std;unsigned char testvals[] =
{14, 0, 0, 0, 13, 0, 0, 0, 9, 0, 0, 0, 6, 0, 0, 0, 19, 0, 0, 0, 5, 0, 0, 0, 88, 0, 0, 0, 86, 0, 0, 0, 62, 0, 0, 0, 6, 0, 0, 0, 12, 0, 0, 0, 60, 0, 0, 0, 31, 0, 0, 0, 87, 0, 0, 0, 20, 0, 0, 0, 107, 0, 0, 0, 87, 0, 0, 0, 89, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102, 0, 0, 0, 107, 0, 0, 0, 99, 0, 0, 0, 100, 0, 0, 0, 127, 0, 0, 0, 97, 0, 0, 0, 103, 0, 0, 0, 100, 0, 0, 0, 59, 0, 0, 0, 86, 0, 0, 0, 107, 0, 0, 0, 97, 0, 0, 0, 123, 0, 0, 0, 38, 0, 0, 0, 59, 0, 0, 0, 80, 0, 0, 0, 99, 0, 0, 0, 95, 0, 0, 0, 77, 0, 0, 0, 90, 0, 0, 0, 113, 0, 0, 0, 12, 0, 0, 0, 55, 0, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};int main()
{char xorvals[] = "hahahaha_do_you_find_me?";string flag = "";for (int i = 0; i < 19; ++i){flag += xorvals[i] ^ testvals[i * 4];}cout << flag << endl;
}
但是只有19位, 还差5位, 在dump出来的程序中再找找发现sub_40159A函数
int __cdecl sub_40159A(int a1)
{unsigned int v1; // eaxchar v3[9]; // [esp+13h] [ebp-15h] BYREFint v4; // [esp+1Ch] [ebp-Ch]strcpy(v3, "%tp&:");v1 = time(0);srand(v1);v4 = rand() % 100;v3[6] = 0;*(_WORD *)&v3[7] = 0;if ( (v3[(unsigned __int8)v3[5]] != *(_BYTE *)((unsigned __int8)v3[5] + a1)) == v4 )return puts("Really??? Did you find it?OMG!!!");elsereturn puts("I hide the last part, you will not succeed!!!");
}
没啥固定逻辑, 剩下5位就摁猜, 因为知道最后一个字符是}, 然后v3 == "%tp&:", 盲猜也是xor, 而且':' ^ '}' == 71
#include <iostream>
#include <string>
using namespace std;int main()
{char xorvals[] = "\%tp&:";string flag = "flag{d07abccf8a410c";for (int i = 0; i < 5; ++i){flag += xorvals[i] ^ 71;}cout << flag << endl;
}
[FlareOn5]Minesweeper Championship Registration
jadx打开, 看到InviteValidator
package defpackage;import java.awt.Component;
import javax.swing.JOptionPane;/* renamed from: InviteValidator reason: default package */
public class InviteValidator {public static void main(String[] args) {String response = JOptionPane.showInputDialog((Component) null, "Enter your invitation code:", "Minesweeper Championship 2018", 3);if (response.equals("GoldenTicket2018@flare-on.com")) {JOptionPane.showMessageDialog((Component) null, "Welcome to the Minesweeper Championship 2018!\nPlease enter the following code to the ctfd.flare-on.com website to compete:\n\n" + response, "Success!", -1);} else {JOptionPane.showMessageDialog((Component) null, "Incorrect invitation code. Please try again next year.", "Failure", 0);}}
}
[羊城杯 2020]easyre

int __cdecl main(int argc, const char **argv, const char **envp)
{int v3; // eaxint v4; // eaxint v5; // eaxchar Str[48]; // [rsp+20h] [rbp-60h] BYREFchar Str1[64]; // [rsp+50h] [rbp-30h] BYREFchar v9[64]; // [rsp+90h] [rbp+10h] BYREFchar v10[64]; // [rsp+D0h] [rbp+50h] BYREFchar Str2[60]; // [rsp+110h] [rbp+90h] BYREFint v12; // [rsp+14Ch] [rbp+CCh] BYREF_main();strcpy(Str2, "EmBmP5Pmn7QcPU4gLYKv5QcMmB3PWHcP5YkPq3=cT6QckkPckoRG");puts("Hello, please input your flag and I will tell you whether it is right or not.");scanf("%38s", Str);if ( strlen(Str) != 38|| (v3 = strlen(Str), (unsigned int)encode_one(Str, v3, v10, &v12))|| (v4 = strlen(v10), (unsigned int)encode_two(v10, v4, v9, &v12))|| (v5 = strlen(v9), (unsigned int)encode_three(v9, v5, Str1, &v12))|| strcmp(Str1, Str2) ){printf("Something wrong. Keep going.");return 0;}else{puts("you are right!");return 0;}
}__int64 __fastcall encode_one(char *a1, int a2, char *a3, int *a4)
{int v5; // esiint v6; // esiint v7; // esiint v8; // [rsp+34h] [rbp-1Ch]int v9; // [rsp+38h] [rbp-18h]int v11; // [rsp+48h] [rbp-8h]int i; // [rsp+4Ch] [rbp-4h]unsigned __int8 *v13; // [rsp+70h] [rbp+20h]v13 = (unsigned __int8 *)a1;if ( !a1 || !a2 )return 0xFFFFFFFFi64;v11 = 0;if ( a2 % 3 )v11 = 3 - a2 % 3;v9 = a2 + v11;v8 = 8 * (a2 + v11) / 6;for ( i = 0; i < v9; i += 3 ){*a3 = alphabet[(char)*v13 >> 2];if ( a2 + v11 - 3 == i && v11 ){if ( v11 == 1 ){v5 = (char)cmove_bits(*v13, 6u, 2u);a3[1] = alphabet[v5 + (char)cmove_bits(v13[1], 0, 4u)];a3[2] = alphabet[(char)cmove_bits(v13[1], 4u, 2u)];a3[3] = 61;}else if ( v11 == 2 ){a3[1] = alphabet[(char)cmove_bits(*v13, 6u, 2u)];a3[2] = 61;a3[3] = 61;}}else{v6 = (char)cmove_bits(*v13, 6u, 2u);a3[1] = alphabet[v6 + (char)cmove_bits(v13[1], 0, 4u)];v7 = (char)cmove_bits(v13[1], 4u, 2u);a3[2] = alphabet[v7 + (char)cmove_bits(v13[2], 0, 6u)];a3[3] = alphabet[v13[2] & 0x3F];}a3 += 4;v13 += 3;}if ( a4 )*a4 = v8;return 0i64;
}__int64 __fastcall encode_two(const char *a1, int a2, char *a3, int *a4)
{if ( !a1 || !a2 )return 0xFFFFFFFFi64;strncpy(a3, a1 + 26, 0xDui64);strncpy(a3 + 13, a1, 0xDui64);strncpy(a3 + 26, a1 + 39, 0xDui64);strncpy(a3 + 39, a1 + 13, 0xDui64);return 0i64;
}__int64 __fastcall encode_three(const char *a1, int a2, char *a3, int *a4)
{char v5; // [rsp+Fh] [rbp-11h]int i; // [rsp+14h] [rbp-Ch]const char *v8; // [rsp+30h] [rbp+10h]v8 = a1;if ( !a1 || !a2 )return 0xFFFFFFFFi64;for ( i = 0; i < a2; ++i ){v5 = *v8;if ( *v8 <= '@' || v5 > 'Z' ){if ( v5 <= '`' || v5 > 'z' ){if ( v5 <= '/' || v5 > '9' )*a3 = v5;else*a3 = (v5 - '0' + 3) % 10 + '0';}else{*a3 = (v5 - 'a' + 3) % 26 + 'a';}}else{*a3 = (v5 - 'A' + 3) % 26 + 'A';}++a3;++v8;}return 0i64;
}
从后往前逆, encode_three是数字和字母移位置换3位, encode_two是每13位数据进行置换, encode_one是base64(看alphabet猜的)
REV
import base64testval = 'EmBmP5Pmn7QcPU4gLYKv5QcMmB3PWHcP5YkPq3=cT6QckkPckoRG'
print(len(testval))
testval = list(testval)for i in range(len(testval)):tmp = testval[i]if not str.isalnum(tmp): continueif str.isalpha(tmp):if str.isupper(tmp):testval[i] = chr(((ord(tmp) - ord('A') - 3) % 26) + ord('A'))else:testval[i] = chr(((ord(tmp) - ord('a') - 3) % 26) + ord('a'))else:testval[i] = chr(((ord(tmp) - ord('0') - 3) % 10) + ord('0'))print(''.join(testval))tempval = [' ' for _ in range(52)]
tempval[13:26] = testval[39:]
tempval[39:] = testval[26:39]
tempval[:13] = testval[13:26]
tempval[26:39] = testval[:13]print(tempval)
tempval = ''.join(tempval)
print(tempval)
flag = base64.b64decode(tempval.encode('utf-8'))
print(flag.decode('utf-8'))
注意 - 写脚本时踩的坑:
%的优先级大于+-;
python3解码base64时, 字符都为unicode编码, 而b64decode函数的参数为byte类型, 所以必须先转码.
还有如果用列表的切片赋值, 会出错, 原因在于浅拷贝, 比如
tempval = testval
testval[13:26] = tempval[39:]
testval[39:] = tempval[26:39]
testval[:13] = tempval[13:26]
testval[26:39] = tempval[:13]
相关文章:
BUUCTF reverse wp 51 - 55
findKey shift f12 找到一个flag{}字符串, 定位到关键函数, F5无效, 大概率是有花指令, 读一下汇编 这里连续push两个byte_428C54很奇怪, nop掉下面那个, 再往上找到函数入口, p设置函数入口, 再F5 LRESULT __stdcall sub_401640(HWND hWndParent, UINT Msg, WPARAM wPara…...
WebGL笔记:使用鼠标绘制多个线条应用及绘制动感线性星座
使用鼠标绘制多个线条 多个线条,肯定不是一笔画过的,而是多次画的线条既然是多线,那就需要有个容器来管理它们 1 )建立容器对象 建立一个 lineBox 对象,作为承载多边形的容器 // lineBox.js export default class …...
nodejs+vue 汽车销售系统elementui
第三章 系统分析 10 3.1需求分析 10 3.2可行性分析 10 3.2.1技术可行性:技术背景 10 3.2.2经济可行性 11 3.2.3操作可行性: 11 3.3性能分析 11 3.4系统操作流程 12 3.4.1管理员登录流程 12 3.4.2信息添加流程 12 3.4.3信息删除流程 13 第四章 系统设计与…...
leetcode76 Minimum Window Substring
给定两个字符串s和t, 找到s的一个子串,使得t的每个字符都出现在子串中,求最短的子串 由于要每个字符出现,所以顺序其实没有关系 因此我们可以定义一个map,统计t中字符出现次数 然后在s中慢慢挪动滑动窗口,…...
简单工厂模式~
我们以生产手机作为应用场景展开讲解! 手机是一个抽象的概念,它包含很多的品牌,例如华为,苹果,小米等等,因此我们可将其抽象为一个接口,如下所示: public interface tel {void pro…...
基于Java的会员管理系统设计与实现(源码+lw+部署文档+讲解等)
文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding)有保障的售后福利 代码参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…...
数据结构 图 并查集 遍历方法 最短路径算法 最小生成树算法 简易代码实现
文章目录 前言并查集图遍历方法广度优先遍历深度优先遍历 最小生成树算法Kruskal算法Prim算法 最短路径算法Dijkstra算法BellmanFord算法FloydWarshall算法 全部代码链接 前言 图是真的难,即使这些我都学过一遍,再看还是要顺一下过程;说明方…...
idea Springboot 教师标识管理系统开发mysql数据库web结构java编程计算机网页源码maven项目
一、源码特点 springboot 教师标识管理系统是一套完善的信息系统,结合springboot框架和bootstrap完成本系统,对理解JSP java编程开发语言有帮助系统采用springboot框架(MVC模式开发),系统 具有完整的源代码和数据库&…...
2023-9-30 JZ36 二叉搜索树与双向链表
题目链接:二叉搜索树与双向链表 import java.util.*; /** public class TreeNode {int val 0;TreeNode left null;TreeNode right null;public TreeNode(int val) {this.val val;}} */ public class Solution {TreeNode pre null;public TreeNode Convert(Tree…...
在windows的ubuntu LTS中安装及使用EZ-InSAR进行InSAR数据处理
EZ-InSAR(曾被称为MIESAR,即Matlab界面用于易于使用的合成孔径雷达干涉测量)是一个用MATLAB编写的工具箱,用于通过易于使用的图形用户界面(GUI)进行干涉合成孔径雷达(InSAR)数据处理…...
腾讯mini项目-【指标监控服务重构】2023-08-25
今日已办 traefik proxy jaeger Prometheus prometheus | Prometheus 配置完依然无法实现 web-url的前缀访问【待解决】 Set span storage type : elasticsearch services:elasticsearch:image: elasticsearch:7.17.12container_name: elasticsearchnetworks:- backend # …...
数据挖掘(1)概述
一、数据仓库和数据挖掘概述 1.1 数据仓库的产生 数据仓库与数据挖掘: 数据仓库和联机分析处理技术(存储)。数据挖掘:在大量的数据中心挖掘感兴趣的知识、规则、规律、模式、约束(分析)。数据仓库用于决策分析: 数据仓库:是在数…...
YApi Pro
1.介绍 说明:YApi Pro 是一款高效、易用、功能强大的 API 管理平台,旨在为开发、产品、测试人员提供更优雅的接口管理服务。它可以帮助开发者轻松创建、发布、维护 API,同时为用户提供了优秀的交互体验,开发人员可以更加高效地完…...
AUTOSAR RTE介绍(更新版230925)
RTE是什么 AUTOSAR RTE(Run Time Environment)实现了AUTOSAR系统中的虚拟功能总线(VFB),提供了SWC(Software Component)之间的访问接口和SWC对于BSW资源的访问接口。RTE为SWC中的Runnable提供与其他SWC或者BSW模块通信的接口,RTE将Runnable映射到OS Task中,并且管理Runna…...
深度学习笔记_1、定义神经网络
1、使用了PyTorch的nn.Module类来定义神经网络模型;使用nn.Linear来创建全连接层。(CPU) import torch.nn as nn import torch.nn.functional as F from torchsummary import summary# 定义神经网络模型 class Net(nn.Module):def __init__(self):super(Net, self).__init__()…...
【Java 进阶篇】MySQL 事务详解
在数据库管理中,事务是一组SQL语句的执行单元,它们被视为一个整体。事务的主要目标是保持数据库的一致性和完整性,即要么所有SQL语句都成功执行,要么所有SQL语句都不执行。在MySQL中,事务起到了非常重要的作用…...
Spring修炼之旅(3)自动装配与注解开发
一、自动装配说明 1.1概述 自动装配是使用spring满足bean依赖的一种方法 spring会在应用上下文中为某个bean寻找其依赖的bean。 1.2装配机制 Spring中bean有三种装配机制,分别是: 在xml中显式配置; 在java中显式配置; 隐式…...
嵌入式Linux应用开发-基础知识-第十六章GPIO和Pinctrl子系统的使用
嵌入式Linux应用开发-基础知识-第十六章GPIO和Pinctrl子系统的使用 第十六章 GPIO 和 Pinctrl 子系统的使用16.1 Pinctrl 子系统重要概念16.1.1 引入16.1.2 重要概念16.1.3 示例16.1.4 代码中怎么引用pinctrl 16.2 GPIO子系统重要概念16.2.1 引入16.2.2 在设备树中指定引脚16.2…...
Ubuntu系统下使用apt-get安装Mysql8
记录一下在Ubuntu20.04 64位系统下面使用apt-get方式安装mysql8关系型数据库 Centos下使用yum安装Mysql8(Mysql5.7)以及常见的配置和使用 首先肯定是检查下当前Ubuntu系统是否已经安装过mysql数据库 一般拿到新的云服务器是没有安装的 rootmyw:~# whe…...
jenkins联动显示或隐藏参数
1. 添加组件 Active Choices Plug-in 如jenkins无法联网,可在以下两个地址中下载插件,然后放到/home/jenkins/.jenkins/plugin下面重启jenkins即可 Active Choices Active Choices | Jenkins plugin 2. 效果如下: sharding为空时…...
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
10-Oracle 23 ai Vector Search 概述和参数
一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI,使用客户端或是内部自己搭建集成大模型的终端,加速与大型语言模型(LLM)的结合,同时使用检索增强生成(Retrieval Augmented Generation &#…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...
OD 算法题 B卷【正整数到Excel编号之间的转换】
文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的:a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...
