【2021.12.25】ctf逆向中常见加密算法和编码识别

news2025/1/15 19:47:46

【2021.12.25】ctf逆向中常见加密算法和编码识别(含exe及wp)

文章目录

  • 【2021.12.25】ctf逆向中常见加密算法和编码识别(含exe及wp)
    • 0、前言
    • 1、基础加密手法
    • 2、base64
      • (1)原理:
      • (2)base64完整编码过程
      • (3)base64完整解码过程
      • (4)特殊情况
      • (5)base64加解密代码
      • (6)base64在ctf中的变换
      • (7)变换码表之后的base解法:
      • (8)base58
      • (9)练习
    • 3、TEA
      • (1)简介
      • (2)TEA加解密代码
      • (3)TEA扩展:XTEA加密
    • 4、RC4
      • (1)简介
      • (2)加密过程
      • (3)RC4加解密代码
      • (4)RC4逆向
      • (5)逆向RC4算法技巧
      • (6)练习
    • 5、MD5
      • (1)简介
      • (2)特点
      • (3)运用
      • (4)ctf逆向中的使用
    • 6、总结

0、前言

在对数据进行变换的过程中,除了简单的字节操作之外,还会使用一些常用的编码加密算法,因此如果能够快速识别出对应的编码或者加密算法,就能更快的分析出整个完整的算法。

CTF 逆向中通常出现的加密算法包括 base64、TEA、AES、RC4、MD5 等。

1、基础加密手法

简单位运算

位运算C语言符号意义
左移<<一般是位左移,低位补零
右移>>一般是位右移,有符号数高位补符号位,无符号数高位补0
异或^按位比较,相同位取0,不同位取1
&按位比较,全为1时取1,否走取0
|按位比较,全为0时取0,否则取1
~按位取反

简单加密类型

基础加密算法简易公式意义
凯撒加密Y=X+a任意值X经过偏移为a的移位变换为Y
仿射加密Y = aX+b与上面类似

2、base64

Base64 是一种基于 64 个可打印字符来表示二进制数据的表示方法。其码表有64个字符。

base64码表

加密的数据分为3个字节一组、6位一段;其中6位的含义是2的6次方=64,可以用64个码表字符表示。

(1)原理:

3个字节一组,将 3 字节的数据,(字符对应Ascll码)先后放入一个 24位的缓冲区中,先来的字节占高位。

3个字节24位从高到低平分成4段,每段6位,

用这6位二进制为代表的数字在base表中查找对应位置的字符。

(2)base64完整编码过程

假设要编码的字符串长度是3的倍数。

image-20210907185026475

(3)base64完整解码过程

假设要解码的字符串长度是4的倍数。

image-20210907185139929

(4)特殊情况

加密字符长度除以3余1 ,则最后一组只有1个字节8位,将8位二进制后续以0填充至12位,(6的倍数),分成两段,查表获得两个字符,再添加‘==’,凑齐4个字符,完整演示如下。

image-20210907185307314

加密字符长度除以3余2,则最后一组只有2个字节16位,将16位二进制后续以0填充至18位,(6的倍数),分成3段,查表获得三个字符,再添加‘=’,凑齐4个字符,完整演示如下。

image-20210907185442061

(5)base64加解密代码

–C语言–

环境:win10

编译:VC++6.0

加密

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

char a[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
char s[100];
int i,j;

void jiami(char x,char y,char z){
	s[j]=a[x>>2];
	s[j+1]=a[(x<<4|y>>4)&0x3f];
	s[j+2]=a[(y<<2|z>>6)&0x3f];
	s[j+3]=a[z&0x3f];
}


int main(){
	int len;
	char str[100];

	printf("base64需要加密的字符串:");
	gets(str);
	len=strlen(str);
	
	for(i=0,j=0;i<=len-3;i+=3,j+=4){
		jiami(str[i],str[i+1],str[i+2]);
	}
	if(len%3==1){
		s[j]=a[str[len-1]>>2];
		s[j+1]=a[str[len-1]<<4&0x3f];
		s[j+2]='=';
		s[j+3]='=';
	}
	if(len%3==2){
		s[j]=a[str[len-2]>>2];
		s[j+1]=a[(str[len-2]<<4|str[len-1]>>4)&0x3f];
		s[j+2]=a[(str[len-1]<<2)&0x3f];
		s[j+3]='=';
	}
	printf("\n加密之后:");
	puts(s);
	printf("\n");
	system("pause");
	return 0;
}

解密

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char s[100];
int i,j;
char a[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

void jiemi(int a,int b,int c,int d)
{
	s[j]=a<<2|b>>4;
	s[j+1]=b<<4|c>>2;
	s[j+2]=c<<6|d;
}

int main()
{
	int len,len1;
	int str1[100];
	char str[100];

	printf("base64需要解密的字符串:");
	gets(str);
	len=strlen(str);
		
	for(i=0;i<len;i++)
		for(j=0;j<64;j++)
			if(str[i]==a[j]){
				str1[i]=j;
				len1=i+1;	}	
	for(i=0,j=0;i<=len1-4;i+=4,j+=3)
		jiemi(str1[i],str1[i+1],str1[i+2],str1[i+3]);

	if(len1%4==2)
		s[j]=str1[i]<<2|str1[i+1]>>4;
	if(len1%4==3){
		s[j]=str1[i]<<2|str1[i+1]>>4;
		s[j+1]=str1[i+1]<<4|str1[i+2]>>2;
	}
	
	printf("\n解密之后:");
	puts(s);
	putchar('\n');
	system("pause");
	return 0;
}

–python–

环境:win10

编译:VScode-python3

python的话就比较简单了,直接调库即可。

image-20210907185856813

image-20210907190143736

(6)base64在ctf中的变换

  1. 替换base64码表

  2. 改写编码过程

    (1)编码之后每一位进行偏移或仿射

    (2)编码时3字节分4段,每段不固定6位, 可以分成 5位 6位 6位 7位 共24位 3字节

    (3)编码不固定3字节一组,也可以4字节32位, 分为6位 6位 7位 7位 6位,共32位

常见base家族

base32,码表32个字符,8个字节一组、5位一段;2的5次方=32

base16,码表16个字符,1个字节一组、4位一段;2的4次方=16

(7)变换码表之后的base解法:

C语言脚本: 直接替换码表即可

python脚本:将编码中字符,与新base64码表和原始base64码表,作一一映射的替换, 再调库进行正常base64解码(原始码表)

import base64
import string
s = "pCNxpTJ2d3d5nPoQnSAAnQBel4lihldkikV78nQ="#base64编码

str1 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/"#base64新的码表
str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"#base64原始码表

trantab  = str.maketrans(str1,str2)#maketrans方法 返回str1与str2一一映射表
#print(type(trantab),trantab )

s_base64 = s.translate(trantab)#translate方法,s的每一个字符,通过上面trantab一一映射表,替换为另一字符串

s_new = base64.b64decode(s_base64).decode('utf-8')
print(s_new)

image-20210907190713710

(8)base58

base58,码表58个字符,将三个字节数值 连起来看做256进制, 再将其转换为4个58进制,对应码表查找字符。

image-20210907231542080

图片参考:编码算法-Base58

(9)练习

base64换表练习

链接:https://pan.baidu.com/s/11Mm_qRxgplp-pKLSWnXPlg
提取码:wqpf

base64算法变换练习

链接:https://pan.baidu.com/s/1ZrsfrSJauYbTAnFd_X0Ang
提取码:qh6u

3、TEA

(1)简介

微型加密算法(Tiny Encryption Algorithm,TEA)是一种易于描述和执行的块密码,通常只需要很少的代码就可实现。由剑桥大学计算机实验室的David Wheeler和Roger Needham于1994年发明。

它是一种分组密码算法,其明文密文块为64比特密钥长度为128比特

TEA算法利用不断增加的Delta(黄金分割率)值作为变化,使得每轮的加密是不同,该加密算法的迭代次数可以改变,建议的迭代次数为32轮。QQ使用此加密技术,加密轮数为16轮。

明文密文块为64比特:一般两个4字节数 (int型)

密钥长度为128比特:一般4个四字节数(int型)

整体的加密过程如下图

image-20210907232940561

图片参考:TEA、XTEA、XXTEA加密解密算法

(2)TEA加解密代码

环境:win10

编译:VC++6.0

建议代码结合上图一起分析。

加密

#include<stdio.h>
void encode(unsigned int* v,unsigned int *k)
{
    unsigned int v0=v[0],v1=v[1];
    unsigned int k0=k[0],k1=k[1],k2=k[2],k3=k[3];
    unsigned int delta=0x9e3779b9;
    int i;
    unsigned int sum=0;
    for(i=0;i<32;i++)          //核心加密算法,建议32轮,最低16轮
    {
        sum+=delta;
        v0+=((v1<<4)+k0)^(v1+sum)^((v1>>5)+k1);     //r<<4/r*16
        v1+=((v0<<4)+k2)^(v0+sum)^((v0>>5)+k3);
    }
    v[0]=v0;
    v[1]=v1;
}
int main()
{
	//明文,必须是8字节的倍数,不够需要程序补全,参考base64方法
    unsigned int m[2]={1,2}; 
    unsigned int k[4]={2,2,3,4};//密钥随便 一定是128位,即4个4字节数
    encode(m,k);
    printf("%d %d\n",m[0],m[1]);
	
	return 0;
}

解密

#include<stdio.h>
#include<windows.h>

void decode(unsigned int* v,unsigned int *k)
{
	unsigned int v0=v[0], v1=v[1], sum=0xC6EF3720, i;  //由加密轮数而算出
    unsigned int delta=0x9e3779b9;                     
    unsigned int k0=k[0], k1=k[1], k2=k[2], k3=k[3]; 
    for (i=0; i<32; i++) {                                    //核心解密算法
        v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
        v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
        sum -= delta;
    }                                           
    v[0]=v0; 
	v[1]=v1;
}
int main()
{
    unsigned int c[2]={1347371722,925494771}; //密文,两字节一组
    unsigned int k[4]={2,2,3,4};//密钥随便 一定是128位,即4个4字节数
    decode(c,k);
    printf("%d %d\n",c[0],c[1]);

	return 0;
}

(3)TEA扩展:XTEA加密

XTEA加密和TEA加密基本类似,只是多了一点点,对比一下代码即可发现。

环境:win10

编译:VC++6.0

加密

#include <stdio.h>   
  
/* take 64 bits of data in v[0] and v[1] and 128 bits of key[0] - key[3] */  
  
void encipher(unsigned int num_rounds, unsigned int v[2], unsigned int key[4]) 
{  
    unsigned int i;  
    unsigned int v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;  
    for (i=0; i < num_rounds; i++) {  
		sum += delta;  
        v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);  
        v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);  
    }  
    v[0]=v0; v[1]=v1;  
}  
  
int main()  
{  
    unsigned int v[2]={1,2};  
    unsigned int k[4]={2,2,3,4};  
    unsigned int r=32;//num_rounds建议取值为32  
    // v为要加密的数据是两个32位无符号整数  
    // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位  
    printf("加密前原始数据:%u %u\n",v[0],v[1]);  
    encipher(r, v, k);  
    printf("加密后的数据:%u %u\n",v[0],v[1]);   
    return 0;  
}  

解密

#include <stdio.h> 

/* take 64 bits of data in v[0] and v[1] and 128 bits of key[0] - key[3] */  

void decipher(unsigned int num_rounds, unsigned int v[2], unsigned int key[4])
{  
    unsigned int i;  
    unsigned int v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*num_rounds;  
    for (i=0; i < num_rounds; i++) {  
		sum -= delta;  
        v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);  
        v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);  
    }  
    v[0]=v0; v[1]=v1;  
}  
  
int main()  
{  
    unsigned int c[2]={1345390024,2801624574};  
    unsigned int k[4]={2,2,3,4};  
    unsigned int r=32;//num_rounds建议取值为32  
    // v为要加密的数据是两个32位无符号整数  
    // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位  
    printf("解密前原始数据:%u %u\n",c[0],c[1]);  
    decipher(r, c, k);  
    printf("解密后的数据:%u %u\n",c[0],c[1]);  
    return 0;  
}  

4、RC4

(1)简介

百度百科:RC4

RC4(来自 Rivest Cipher 4 的缩写)是一种流加密算法密钥长度可变。它加解密解密使用相同的密钥,因此也属于对称加密算法。RC4 是有线等效加密(WEP)中采用的加密算法,也曾经是 TLS可采用的算法之一。

特点:

名称特点
秘钥长度可变,通常小于256字节
密钥流指S盒,长度256Byte,初始化为0~255序列,然后根据秘钥K搅乱
明文长度任意,明文只一次异或加密

(2)加密过程

image-20210908001318799

注意看加密过程,明文就一个异或加密

只是密钥流要当时生成,加密解密的密钥流都是一样的

完整加密过程

结合上图

image-20210908001437128

注意: 加密前,生成的密钥流s盒,加密后密钥流s盒会发生改变,所以解密时,用的密钥流s盒是初始化之后但加密前的,即上图第一步之后生成的s盒。

(3)RC4加解密代码

先初始化秘钥

image-20210908001536375

再进行加解密,(用的秘钥都是上述代码初始化出来的)

image-20210908001710735

完整加密代码

环境:win10

编译:VC++6.0

main函数有通过RC4加解密的整个过程

//程序开始
#include<stdio.h>
#include<string.h>
 
/*初始化函数*/
//参数1:传入长度256的unsigned char型数组首地址
//参数2:密钥,其内容可以随便定义:char key[256];
//参数3是密钥的长度,Len = strlen(key);
void rc4_init(unsigned char*s, unsigned char*key, unsigned long Len)
{
    int i = 0, j = 0;
    char k[256] = { 0 };
    unsigned char tmp = 0;
    for (i = 0; i<256; i++)
    {
        s[i] = i;//初始化s盒,0~255
        k[i] = key[i%Len];
    }
    for (i = 0; i<256; i++)//将s盒打乱
    {
        j = (j + s[i] + k[i]) % 256;
		
        tmp = s[i];//交换s[i]和s[j]
        s[i] = s[j];  
        s[j] = tmp;
    }
}
 
/*加解密*/
//参数1:是上边rc4_init函数中,被搅乱的S-box;
//参数2:是需要加密/解密的数据data;
//参数3:data的长度.
void rc4_crypt(unsigned char*s, unsigned char*Data, unsigned long Len)
{
    int i = 0, j = 0, t = 0;
    unsigned long k = 0;
    unsigned char tmp;
    for (k = 0; k<Len; k++)
    {
        i = (i + 1) % 256;
        j = (j + s[i]) % 256;
        tmp = s[i];
        s[i] = s[j];//交换s[x]和s[y]
        s[j] = tmp;

        t = (s[i] + s[j]) % 256;
        Data[k] ^= s[t];
    }
}
 
int main()
{
    unsigned char s[256] = { 0 }, s2[256] = { 0 };//S-box
    char key[256] = { "justfortest" };
    unsigned char pData[512] = "Hello World";
    unsigned long len = strlen((char*)pData);
    int i;
 
    printf("pData=%s\n", pData);
    printf("key=%s,length=%d\n\n", key, strlen(key));
    rc4_init(s, (unsigned char*)key, strlen(key));//已经完成了初始化
    printf("完成对S[i]的初始化,如下:\n\n");
    for (i = 0; i<256; i++)
    {
        printf("%02X", s[i]);
        if (i && (i + 1) % 16 == 0)putchar('\n');
    }
    printf("\n\n");
    for (i = 0; i<256; i++)//用s2[i]暂时保留经过初始化的s[i],很重要的!!!
    {
        s2[i] = s[i];
    }
    printf("已经初始化,现在加密:\n\n");
    rc4_crypt(s, (unsigned char*)pData, len);//加密
	for(i=0;pData[i];i++){
		printf("0x%x,",pData[i]);
	}
    //printf("pData=%s\n\n", pData);
	printf("\n");
    printf("已经加密,现在解密:\n\n");
    //rc4_init(s,(unsignedchar*)key,strlen(key));//初始化密钥
    rc4_crypt(s2, (unsigned char*)pData, len);//解密
    printf("pData=%s\n\n", pData);
    return 0;
}
 
//程序完

(4)RC4逆向

上述可以看出RC4算法,加密和解密是一样的流程

先初始化密钥流S盒,再通过初始化的密钥流S盒对数据进行异或加密/解密

所以逆向RC4算法:找到密钥、加密之后的数据,用来跑一边解密脚本

(5)逆向RC4算法技巧

image-20210908002309988

image-20210908002304517

通过上面两张图可以看到:

密文=明文^密钥流

所以!明文=密文^密钥流

即密钥固定时,每次加密生成的秘钥流是固定的

**解密难点:**密钥流未知

技巧:

我们可以通过选择明文攻击

即输入一串已知明文,调试获取加密之后的密文

这样就已知了明文和对应密文

所以可求:密钥流=已知明文^对应密文

然后根据原始密文

可求得:原始明文=原始密文^密钥流

(6)练习

RC4练习

链接:https://pan.baidu.com/s/1nblRiYkSFewKRyulSirUXg
提取码:ffyq

5、MD5

(1)简介

MD5 消息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个 128 位(16 字节)的散列值(hash value),用于确保信息传输完整一致

(2)特点

1、无论加密数据多大多小,都只生成长度一样的散列值(一般是128位,16字节)

2、相同的数据,随时生成的散列值都一致,但只要数据发生一点变化,生成的散列值差别巨大

3、MD5本身不可逆

(3)运用

1、密码管理,输入密码后进行md5加密然后与数据库中的md5值对比(易受到md5撞库攻击)

2、电子签名,确保数据传输过程中数据更改

(4)ctf逆向中的使用

在线md5加密网址:https://www.somd5.com/

6、总结

ctf逆向中的加密算法坑定不止上述这些,只是说通过这些简单的加密算法,学习,进阶,再难的算法都是从基础算法变换而来的,好比万丈高楼平地起!加油!

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

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

相关文章

利用出厂状态下的闲置主机配置HP M1136打印机

利用出厂状态下的闲置主机配置HP M1136打印机 打印机型号&#xff1a;LaserJet M1136 MFP 主机状态&#xff1a;出厂状态&#xff0c;C盘及储存盘被分成了5片 网络环境&#xff1a;与打印机相连的主机全程无Internet连接&#xff0c;主机处于离线状态。打印机驱动及一些相关软…

Splunk 成功获取Salesforce 数据

1: 先说一下Splunk server 上要安装Splunk Add-on for Salesforce : (https://splunkbase.splunk.com/) 去下载: https://splunkbase.splunk.com/app/3549 2: 下载安装后,看到如下界面: 3: 官方的指导文档: Configure your Salesforce account to collect data…

0301_对应的南京比特物联网

0301_对应的南京比特物联网目录概述需求&#xff1a;设计思路实现思路分析1.流程拓展实现性能参数测试&#xff1a;参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better …

C#的Version类型值与SQL Server中二进制binary类型转换

使用C#语言编写的应用程序可以通过.NET Framework框架提供的Version类来控制每次发布的版本号&#xff0c;以便更好控制每次版本更新迭代。 版本号由两到四个组件组成&#xff1a;主要、次要、内部版本和修订。 版本号的格式如下所示&#xff0c; 可选组件显示在方括号 ([ 和…

UML 时序图

时序图&#xff08;Sequence Diagram&#xff09;是显示对象之间交互的图&#xff0c;是按时间顺序排列的。 时序图中显示的是参与交互的对象及其对象之间消息交互的顺序。 时序图包括的建模元素主要有&#xff1a;对象&#xff08;Actor&#xff09;、生命线&#xff08;Lif…

项目实战典型案例19——临时解决方案和最终解决方案

临时解决方案和最终解决方案一&#xff1a;背景介绍二&#xff1a;思路&方案四&#xff1a;总结五&#xff1a;升华一&#xff1a;背景介绍 本篇博客是对项目开发中出现的临时解决方案和最终解决方案进行的总结和改进。目的是将经历转变为自己的经验。通过博客的方式分享给…

(蓝桥真题)最长不下降子序列(权值线段树)

样例输入&#xff1a; 5 1 1 4 2 8 5 样例输出&#xff1a; 4 分析&#xff1a;看到这种对其中连续k个数进行修改的我们就应该想到答案是由三部分组成&#xff0c;因为求的是最长不下降子序列&#xff0c;那么我们可以找到一个最合适的断点i&#xff0c;使得答案是由区间[1…

【信息安全案例】——网络信息面临的安全威胁

&#x1f4d6; 前言&#xff1a;2010年&#xff0c;震网病毒&#xff08;Stuxnet&#xff09;席卷全球工业界。其目标是从物理上摧毁一个军事目标&#xff0c;这使得网络武器不仅仅只存在于那个人类创造的空间。网络武器的潘多拉魔盒已经打开。 目录&#x1f552; 1. 信息、信息…

28个精品Python爬虫实战项目

先来说说Python的优势&#xff01;然后给大家看下这28个实战项目的实用性&#xff01;Python跟其他语言相比&#xff0c;有以下优点&#xff1a;1. 简单Python是所有编程语言里面&#xff0c;代码量最低&#xff0c;非常易于读写&#xff0c;遇到问题时&#xff0c;程序员可以把…

学习 Python 之 Pygame 开发魂斗罗(八)

学习 Python 之 Pygame 开发魂斗罗&#xff08;八&#xff09;继续编写魂斗罗1. 创建敌人类2. 增加敌人移动和显示函数3. 敌人开火4. 修改主函数5. 产生敌人6. 使敌人移动继续编写魂斗罗 在上次的博客学习 Python 之 Pygame 开发魂斗罗&#xff08;七&#xff09;中&#xff0…

通信网络-Socket、Java中的网络支持、多线程服务器

前言 通信网络-Socket、Java中的网络支持、多线程服务器 场景&#xff1a;使用java网络创建一个聊天室 博客地址&#xff1a;芒果橙的个人博客 文章目录前言通信网络-SocketTCP/IPTCP/IP 模型端口Java中的网络支持概念1. InetAddress2. URL3. Socket4. Datagram多线程服务器应用…

使用ECharts打造一个数据可视化面板

使用ECharts打造一个数据可视化面板1. 使用技术2. 案例适配方案3. 基础设置4. header 布局5. mainbox 主体模块6. 公共面板模块 panel7. 柱形图 bar 模块&#xff08;布局&#xff09;8. 中间布局9. ECharts 介绍10. ECharts 体验11. ECharts 基础配置12. 柱状图图表&#xff0…

MDK软件使用技巧

本文主要汇总MDK软件使用技巧 一、字体大小及颜色修改 第一步点击工具栏的这个小扳手图标 进去后显示如下&#xff0c;先设置 Encoding 为&#xff1a;Chinese GB2312(Simplified)&#xff0c;然后设置 Tab size 为&#xff1a;4 以更好的支持简体中文&#xff0c;否则&…

Java 多线程 --- 线程协作 wait/notify

Java 多线程 --- 线程协作 wait/notifywait / notifyObject.wait() , Object.notify() / notifyAll()notify 和 wait 的原理notify会导致死锁的问题wait / notify的开销以及问题wait / notify 在多线程中, 如果程序拿到锁之后, 但是没有满足指定条件而不能继续往下执行, 我们可…

外网用户打不开公司的网站?web服务器端口映射到公网

我们经常会遇到这样的情景&#xff0c;在公司内部可以打开公司的网站&#xff0c;在家里或者外网却打不开&#xff0c;按照网上的做法&#xff0c;重新启动了服务器和iis&#xff0c;还是不行。许多用户设置了路由器端口映射功能&#xff0c;但是端口映射不成功怎么办&#xff…

2023河南新乡市第二届职业技能大赛“网络安全”项目B模块比赛任务书

2023河南新乡市第二届职业技能大赛“网络安全”项目 比赛任务书一、竞赛时间二、竞赛阶段及内容B-1 Windows操作系统渗透测试B-2 Wireshark数据包分析B-3 CMS网站渗透B-4 未公开B-5 未公开一、竞赛时间 总计&#xff1a;180分钟 二、竞赛阶段及内容 &#xff08;一&#xff…

嵌入式系统实验——【玄武F103开发板】实现两个LED小灯闪烁

目录一、实验文件main.cstm32f10x.h二、实验思路&#xff08;一&#xff09;打开两个LED小灯1.在玄武F103开发板上找到LED0、LED1对应的GPIO控制寄存器2.找到GPIOB、GPIOE的地址3.打开APB2外设时钟的使能寄存器4.对GPIO寄存器进行设置对端口输出寄存器进行设置&#xff08;二&a…

Go语言基准测试(benchmark)三部曲之三:提高篇

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码)&#xff1a;https://github.com/zq2599/blog_demos 本篇概览 -《Go语言基准测试(benchmark)三部曲》已近尾声&#xff0c;经历了《基础篇》和《内存篇》的实战演练&#xff0c;相信您已熟练掌握了基准测试的常…

Spring Security 实现自定义登录和认证(1)

1 SpringSecurity 1.1 导入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId> </dependency>1.2 编写配置类 在spring最新版中禁用了WebSecurityConfigurerAdapter…

《Linux运维实战:基于ansible一键离线部署容器版MySQL一主两从集群(5.6.50、5.7.30、8.0.30)》

一、部署背景 由于业务系统的特殊性&#xff0c;我们需要针对不同的客户环境部署 MySQL主从复制集群&#xff0c;由于大都数用户都是专网环境&#xff0c;无法使用外网&#xff0c;为了更便捷&#xff0c;高效的部署&#xff0c;针对业务系统的特性&#xff0c;我这边编写了基于…