(2023.7.24)软件加密与解密-2-1-程序分析方法[XDbg].md
body { font-size: 15px; color: rgba(51, 51, 51, 1); background: rgba(255, 255, 255, 1); font-family: Helvetica, Arial, "PingFang SC", "Microsoft YaHei", "WenQuanYi Micro Hei", "tohoma,sans-serif"; margin: 0; padding: 10% }
h1 { font-size: 2.2em; font-weight: 700; line-height: 1.1; padding-top: 16px; margin-bottom: 4px }
h2, h3, h4, h5, h6 { line-height: 1.5em; margin-top: 2.2em; margin-bottom: 4px }
h2 { color: rgba(255, 255, 255, 1) !important; background-color: rgba(255, 155, 152, 1); border-left: 12px solid rgba(255, 126, 121, 1); padding: 1px 1px 1px 20px }
h3 { font-weight: 700; font-size: 1.2em; line-height: 1.4; margin: 10px 0 5px; padding-top: 10px }
h4 { font-weight: 700; text-transform: uppercase; font-size: 1.1em; line-height: 1.4; margin: 10px 0 5px; padding-top: 10px }
h5, h6 { font-size: 0.9em }
h5 { font-weight: bold; text-transform: uppercase }
h6 { font-weight: normal; color: rgba(170, 170, 170, 1) }
img { width: 100%; border-radius: 5px; display: block; margin-bottom: 15px; height: auto }
dl, ol, ul { margin-top: 12px; margin-bottom: 20px; padding-left: 5%; line-height: 1.8 }
p { margin: 0 0 20px; padding: 0; line-height: 1.8 }
a { color: rgba(242, 47, 39, 1); text-decoration: none }
a:hover { color: rgba(245, 88, 82, 1); text-decoration: underline }
a:focus { outline-offset: -2px }
blockquote { font-size: 1em; font-style: normal; padding: 30px 38px; margin: 0 0 15px; position: relative; line-height: 1.8; text-indent: 0; border: none; color: rgba(136, 136, 136, 1) }
blockquote:before { content: "“"; left: 12px; top: 0; color: rgba(224, 224, 224, 1); font-size: 4em; font-family: Arial, serif; line-height: 1em; font-weight: 700; position: absolute }
blockquote:after { content: "”"; right: 12px; bottom: -31px; color: rgba(224, 224, 224, 1); font-size: 4em; font-family: Arial, serif; line-height: 1em; font-weight: 700; position: absolute }
strong, dfn { font-weight: 700 }
em, dfn { font-style: italic; font-weight: 400 }
del { text-decoration: line-through }
pre { margin: 0 0 25px; font-size: 13px; line-height: 1.42857; word-break: break-all; word-wrap: break-word; border-radius: 4px; white-space: pre-wrap; display: block; background: rgba(248, 248, 248, 1); padding: 10px 20px; border: none; color: rgba(102, 102, 102, 1); font-family: Courier, sans-serif }
code { color: rgba(199, 37, 78, 1); background-color: rgba(249, 242, 244, 1); border-radius: 4px; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; padding: 2px 4px; font-size: 90% }
p>code { color: rgba(199, 38, 78, 1); background-color: rgba(249, 242, 244, 1); font-size: 0.95em; border-radius: 3px; -moz-border-radius: 3px; -webkit-border-radius: 3px }
figure { margin: 1em 0 }
figcaption { font-size: 0.75em; padding: 0.5em 2em; margin-bottom: 2em }
figure img { margin-bottom: 0 }
hr { border: 0; height: 1px; background: linear-gradient(90deg, rgba(204, 204, 204, 1), rgba(51, 51, 51, 1), rgba(204, 204, 204, 1)) rgba(51, 51, 51, 1) }
ol p, ul p { margin-bottom: 0 }
li { margin-bottom: 0.75em; margin-top: 0.75em }
ol#footnotes { font-size: 0.95em; padding-top: 1em; margin: 20px 0; border-top: 1px solid rgba(234, 234, 234, 1); counter-reset: footer-counter 0; list-style: none; color: rgba(85, 85, 85, 1); padding-left: 5% }
ol#footnotes li { margin-bottom: 10px; margin-left: 16px; font-weight: 400; line-height: 2; list-style-type: none }
ol#footnotes li:before { content: counter(footer-counter) ". "; counter-increment: footer-counter 1; font-weight: 800; font-size: 0.95em }
@keyframes highfade { 0% { } 20% { background-color: rgba(255, 255, 0, 1) } 100% { } }
@-webkit-keyframes highfade{0%{background-color:none}20%{background-color:yellow}100%{background-color:none}}
a:target, ol#footnotes li:target, sup a:target { animation-name: highfade; animation-duration: 2s; animation-iteration-count: 1; animation-timing-function: ease-in-out; -webkit-animation-name: highfade; -webkit-animation-duration: 2s; -webkit-animation-iteration-count: 1; -webkit-animation-timing-function: ease-in-out }
a:target { border: 0; outline: 0 }
a:target { border: 0; outline: 0 }
a:target { border: 0; outline: 0 }
每天一个技术点
(2023.7.24)软件加密与解密-2-1-程序分析方法[XDbg]
本文作者:XDbgPYG(小吧唧)
发布时间:2023年7月24日
内容概要:练一道题
img { box-shadow: 0 0 2px rgba(6, 24, 44, 0.4), 0 4px 6px -1px rgba(6, 24, 44, 0.65), inset 0 1px rgba(255, 255, 255, 0.08) }
0. 收集信息
程序名:CrackMeDemo.tvmp.1.exe
程序界面长相如下:
程序内存长相如下:
程序内存字符串长相如下:
看样子是个 MFC 程序(“应用程序向导生成的本地应用程序”、“CWINAPP”)
除此之外有用的信息似乎就是 “恭喜你,注册成功!” 了。
1.反调试
1.1 学习反调试
扔进 OllyDbg 里,F9跑起来。
查看 OllyDbg 日志,并无太多有用信息,只是知道它跑了俩个异常。
- 浮点数除以零
- 内存访问违规
嗯。。想想有没有办法定位反调试代码范围。
通过例子来学习反调试,点击图片开始学习。
这是我刚才 CV 过来的反调试例子。看样子我们可以试试通过 API 断点,来定位反调试。
if (IsDebuggerPresent())
ExitProcess(-1);
BOOL bDebuggerPresent;
if (TRUE == CheckRemoteDebuggerPresent(GetCurrentProcess(), &bDebuggerPresent) &&
TRUE == bDebuggerPresent)
ExitProcess(-1);
1.2 跟踪反调试
在 CheckRemoteDebuggerPresent 函数下断点,程序断下后,Ctrl + F9 出 CALL。
似乎走到了 ".tvm" 这个代码段来了,简单的使用下我们在日后编写的分析工具 - “基于 CPU 模拟的 xxx ” 。
好的,成功模拟到了 0x040157A 这个地址。通过反汇编代码可以看出,这个代码块似乎含有多个反调试函数,有俩个 jcc 指令跳转到了含有 CALL ExitThread 指令的基本块。
F9 运行到 0x040157A 里,由于我们的反反调试插件强大,所以CheckRemoteDebuggerPresent 返回了 0 ,即程序未被调试的意思。
继续模拟程序,运行到 IsDebuggerPresent 函数中。嗯,是刚才我们学过的反调试内容。
1.3 总结 Call 运行流程
1.3.0 随便看看
将程序扔入 IDA 中 F5 继续分析。根据 IDA 提供的符号,我们大致可以看出这个反调试是在执行 MFC m = new M(b,c) 后才开始检测的。这个信息对于我们完整还原这个程序至关重要,没错,我想把这个程序还原掉~
1.3.1 检测到调试后会执行什么?
让我们看看程序检测调试到后会做些什么?
发现有个 sub_4031f0 call,学过设计模式的朋友应该知道单例模式:即一个类负责一个功能。所以 sub_403530 我是优先不管的。
if ( cObf_CheckRemoteDebug() == 1 || cObf_IsDebug() == 1 )
{
v4 = sub_403530(1); // thiscall 不用理他,估计就是销毁 Dialog 用的。
sub_4031F0(v4); // cdeclCall 有点意思~
ExitThread(8u);
}
对 sub_4031f0 扫引用,发现有个未被 Ida 识别成函数的地址(0x4021B6)。
转到 0x4021B6 看看,发现有个 call MessageBoxA ,字符串参数为 byte_428D64 。
用 OD 转到 byte_428D64 看看是什么内容。运气不错,直逼关键内容。
让我们对 0x4021B6 附近的代码进行简单的分析。发现一个循环代码,跳转到 loc_401F9A 看看。
发现了一个立即数:8。(如果你足够细心就可以发现,这是我们可输入的用户名的最大长度)
看样子关键算法代码,我们已经定位到了,即在 0x00401FA9 附近。
1.4 拿下第一个符号:MFC_INIT
经过刚才的分析,我们基本可以判断这个 Call 是在做 MFC 初始化 + AntiDebuger 操作了。将其记录下来~ 这是我们逆向出来的第一个符号。这是一个重要的阶段性胜利。
1.5 Patch 掉反调试
这里用最容易被 Anti 掉的过检测方式来过掉反调试。将其 leave ret 即可过掉反调试。(还有内存校验没有解决)
可以看到,这里程序已经正常运行了。hiahia。
2. 逆向算法
OD 转到 0x00401FA9 下查看情况,似乎 IDA 有好多代码没有识别出来,有点小尴尬哈。
找了下函数头部 0x00401B35 ,回到 IDA ,一路选中未识别的代码,按下 C 键完成格式转换。
先静态分析看看函数的控制流程好了,在这里我给出我认为简洁有用的信息。
.text:00401DA6 call ?UpdateData@CWnd@@QAEHH@Z ; CWnd::UpdateData(int)
.text:00401DFC call ?GetDlgItem@CWnd@@QBEPAV1@H@Z ; CWnd::GetDlgItem(int)
.text:00401E1F call ?GetDlgItem@CWnd@@QBEPAV1@H@Z ; CWnd::GetDlgItem(int)
.text:00401E9A cmp dword ptr [ebp-8C4h], 8
.text:00401EA1 jge short loc_401F21
.text:00402204 repe cmpsd
.text:00402206 jnz short loc_40221C
.text:00402208 push 0 ; unsigned int
.text:0040220A push 0 ; lpCaption
.text:0040220C push offset Text ; lpText
.text:00402211 mov ecx, [ebp-8D0h] ; this
.text:00402217 call ?MessageBoxA@CWnd@@QAEHPBD0I@Z ; CWnd::MessageBoxA(char const *,char const *,uint)
用 OD 看看和 MsgBoxA 有关的信息 text:00402204 repe cmpsd。经过测试,发现算法不允许输入中文字符串,尴尬了。
uN: XXXXXDbg
pW: EasyXEasyXEasyXEasyXEasyXEasyXEasyXEasyXEasyX
程序是明码比较,这似乎意味着我们在算法部分可以轻松一下了 O(∩_∩)O。
用 IDA 进行 F5 操作。嗯,好模糊的代码,看样子需要清理花指令才能看清楚。(可是现在已经是 22:11:38 了,一天要结束了,就不写脚本清理了)
数了下大致的代码行数,只有 213 行汇编,直接用 OD 调试还原掉好了。
好了,回到让我们到 0x0401E9A 下断点.
.text:00401E9A cmp dword ptr [ebp-8C4h], 8
.text:00401EA1 jge short loc_401F21
经过我努力的跟踪,还原出了如下代码,发现程序获取了代码段的内容并参与到了算法的计算当中,真是个不错的设计。
这样做的话,程序如果直接爆破,生成出来的 serial 必然是错的,难怪程序会直接明码比较,原来暗藏着一股气。
打开 VS ,编写我们的第一段 KeyGen。
// KeyGen.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
unsigned char t[0x0010] =
{
0xf7, 0xff, 0xff, 0x89, 0x8d, 0x4c, 0xf7, 0xff, 0xff, 0xc7, 0x85, 0x48, 0xf7, 0xff, 0xff, 0x14
};
unsigned char t2[0x0010] =
{
0x07, 0x82, 0x19, 0xe8, 0x1f, 0xfe, 0xff, 0xff, 0x0f, 0xb6, 0xd0, 0x85, 0xd2, 0x74, 0x05, 0xe9
};
void getUn2(unsigned char* _un, unsigned char* _un2)
{
unsigned char* un = _un;
unsigned char* un2 = _un2;
for (size_t i = 0; i < 8; i++)
{
int a = (int)*(char*)(t+i);
int a2 = (int)*(char*)(un + i) ^ i;
un2[i] = a2 ^ a;
int b = (int)*(char*)(t2 + i);
int b2 = (int)*(char*)(un2 + i) ;
un2[i] = b2 ^ b;
}
}
int main()
{
std::cout << "Hello KeyGen!\n";
unsigned char uN[] = "XXXXXDbg";
unsigned char* uN2 = new unsigned char[sizeof(uN)];
getUn2(uN,uN2);
return 0;
}
a8 24 bc 3a ce f3 4c 40 // cd fd fd fd
A8 24 BC 3A CE F3 4C 40 // 00 00 00 00
可以看到结果完全正确,让我们继续还原。发现了一个未知的值,[EBP - 0x828],OD 往上翻翻,看看它的算法。
可以看到一个循环很多次的代码,结合刚才的经验,可以看出这个 constV 也是通过代码段的内容算出来的。
这个函数就不用还原了,取消所有软件断点,然后在 0x0401C53 下硬件执行断点,拿到 constV 即可。
constV = 0xCF238EE8;
int constV = 0xCF238EE8;
*(int*)((int*)uN2) ^= constV;
*(int*)((int*)uN2+1) ^= constV;
接下来又是一个循环,估计又有好多表要 CV 下来,哈哈,可以看到依旧循环 8 次。
继续单步~发现了三个 flag 将这段汇编还原成 C 代码~。
还原代码如下。
for (size_t i = 0; i < 8; i++)
{
flag1 = ((uN2[i] & 0xE0) + (((uN2[i] & 0xE0 )>> 24) & 0x1F)) >> 5;
flag2 = (uN2[i] & 0x1C) + (((uN2[i] & 0x1C) >> 24) & 3) >> 2;
flag3 = uN2[i] & 0x3;
int flag4 = i / 3;
int id = i >> 24;
if (id == 2)
{
// .......
}
if (id == 1)
{
// .......
}
if (id == 0)
{
// .......
}
}
继续单步跟踪,在这块代码中,我们发现几张 table 和新的 flag ,翻翻汇编代码看看 flag 有什么意义。
联系上文可以发现,它存储的就是正确的注册码 Serial。
将 table dump 出来将这个基本块还原成 C 代码。
unsigned char t3_834[0x0040] =
{
0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x40, 0xed, 0x9f, 0xf5,
0x26, 0x3a, 0x6f, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
unsigned char t4_87c[0x00B0] =
{
0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7a, 0x6e, 0x69, 0xc9, 0x1b, 0x40, 0x00, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x48, 0x49, 0x18, 0x00, 0xa0, 0xf0, 0x18, 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
0x59, 0x5a, 0x00, 0x00, 0x40, 0xed, 0x9f, 0xf5, 0x26, 0x3a, 0x6f, 0x8f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
unsigned char t5_864[0x0090] =
{
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x18, 0x00, 0xa0, 0xf0, 0x18, 0x00,
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x40, 0xed, 0x9f, 0xf5,
0x26, 0x3a, 0x6f, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
if (id == 0)
{
serial[i] = t3_834[flag2];
serial[i+1] = t4_87c[flag3];
serial[i+2] = t5_864[flag1];
}
好了,接下来我们继续还原其他分支,这是 id == 1 的情况。
还原代码如下。
if (id == 1)
{
serial[i] = t3_834[flag1];
serial[i + 1] = t4_87c[flag2];
serial[i + 2] = t5_864[flag3];
}
这是 id == 2 的情况,发现了俩张新的 table:t6、t7 。
将新的 table dump 下来,还原 C 代码如下。
unsigned char t6_83c[0x001E] =
{
0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
0x59, 0x5A, 0x7F, 0x00, 0xF6, 0x9A, 0xE2, 0xF7, 0x9B, 0x50, 0x09, 0x80, 0x00, 0x00
};
unsigned char t7_874[0x003C] =
{
0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x19, 0x00, 0xC9, 0x1B, 0x40, 0x00,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00,
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C
};
if (id == 2)
{
serial[i] = t5_864[flag3];
serial[i+ 1] = t6_83c[flag1];
serial[i + 2] = t7_874[flag2];
}
在测试的时候,发现 serial 对不上,原因是因为我忘记还原这条汇编指令了、flag4 和 id 的关系搞错了 、constV 提取错了。
IMUL EAX, EAX, 0x3
//int constV = 0xCF238EE8;
int constV = 0xE0698E5C;
int flag4 = i % 3;
int id = flag4;
最终输出结果如下。
XXXXXDbg
Vi7Vk21OvWk6Um21LxRj0Ui0
show time
3. tvm?
看样子这个程序被巧妙的绕过了未知的 vm 保护,实际上经过我的测试,这个程序并无 vm 保护,有基于堆栈的花指令混淆。
这在学习第三章也就是下一章代码混淆时,会将其清除~
4. 还原程序
日后再补。
5. 文件下载
(2023.7.24)软件加密与解密-2-1-程序分析方法[XDbg].md的更多相关文章
- RSA加密、解密、公钥私钥生成
有时项目中需要用到一些加密和解密工具,这里之前整理了一个demo,记录一下,方便查询 package com.test; import java.security.KeyFactory; import ...
- Flash型单片机的加密与解密
厂商利用单片机进行产品开发时,都会关心其代码和数据的保密性.考虑到用户在编写和调试代码时所付出的时间和精力,代码的成本是不言而喻的. 早期的单片机,代码是交给芯片制造商制成掩膜ROM.有两种加密 ...
- RSA js加密 java解密
1. 首先你要拥有一对公钥.私钥: ``` pubKeyStr = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC1gr+rIfYlaNUNLiFsK/Kn ...
- C#.NET中对称和非对称加密、解密方法汇总--亲测可用
C#.NET中对称和非对称加密.解密方法汇总--亲测可用 在安全性要求比较高的系统中都会涉及到数据的加密.解密..NET为我们封装了常用的加密算法,例如:MD5,DES,RSA等.有可逆加密,也有 ...
- Security基础(二):SELinux安全防护、加密与解密应用、扫描与抓包分析
一.SELinux安全防护 目标: 本案例要求熟悉SELinux防护机制的开关及策略配置,完成以下任务: 将Linux服务器的SELinux设为enforcing强制模式 在SELinux启用状态下, ...
- C#加密与解密(DES\RSA)学习笔记
本笔记摘抄自:https://www.cnblogs.com/skylaugh/archive/2011/07/12/2103572.html,记录一下学习过程以备后续查用. 数据加密技术是网络中最基 ...
- Java_DES 加密和解密源码
Java密码学结构设计遵循两个原则: 1) 算法的独立性和可靠性. 2) 实现的独立性和相互作用性. 算法的独立性是通过定义密码服务类来获得.用户只需了解密码算法的概念,而不用去关心如何实现这些概念. ...
- Java实现文件的加密与解密
最近在做一个项目,需要将资源文件(包括图片.动画等类型)进行简单的加密后再上传至云上的服务器,而在应用程序中对该资源使用前先将读取到的文件数据进行解密以得到真正的文件信息.此策略的原因与好处是将准备好 ...
- Java Base64加密、解密原理Java代码
Java Base64加密.解密原理Java代码 转自:http://blog.csdn.net/songylwq/article/details/7578905 Base64是什么: Base64是 ...
- JS URL 使用base64加密与解密
JS编码方式: <script type="text/javascript"> document.write(encodeURI("http://www.w3 ...
随机推荐
- 基于Sentinel自研组件的系统限流、降级、负载保护最佳实践探索
作者:京东物流 杨建民 一.Sentinel简介 Sentinel 以流量为切入点,从流量控制.熔断降级.系统负载保护等多个维度保护服务的稳定性. Sentinel 具有以下特征: 丰富的应用场景:秒 ...
- FPGA输出时钟jitter
If customer performs simple clock forwarding from clock source -> FPGA clock input -> FPGA clo ...
- wait_timeout and interactive_timeout 参数
wait_timeout and interactive_timeout 参数 非交互模式连接:通常情况下,应用到RDS实例会采用非交互模式,具体采用哪个模式需要查看应用的连接方式配置,比如PHP通过 ...
- STL-deque(ACM)
1.两段都可以插入和删除(头 插入删除 尾 插入删除) 普通队列无法用pop_back()删除队列最后的元素,类似地,由于普通队列只能插入头删除,所以push().pop()无需带_front()._ ...
- Python modbus_tk 库源码分析
modbus_tk 源代码分析 前言 modbus_tcp 协议是工业项目中常见的一种基于 TCP/IP 协议的设备数据交互协议. 作为 TCP/IP 协议的上层协议,modbus_tcp 协议涉及到 ...
- java反射机制原理及应用
java反射机制 反射机制原理示意图 Class.forName(字节码文件) 类.class 对象.getClass() 用法: 根据配置的properties文件(不仅是properties) ...
- 用JavaScript撸一个静态链表
最近重新开始翻起<大话数据结构>,看到了静态链表部分里面讲C语言是利用数组模拟,觉得十分有趣.但是在JavaScript中,也可以用类似的方式去实现,定义一个数据域和一个结点域,然后实现链 ...
- 屏蔽CSDN百度广告
最近在查询一些技术问题访问到CSDN时一直弹一些令人作恶的广告,说个特别的广告,脱发广告,特别有针对性程序员同胞们的共性问题,不过还是特别恶心,百度了一下,大家也特别反感,CSDN你真这么缺钱?废话不 ...
- java端口被占用解决办法
- js中数组的方法,32种方法
数组的32中方法=>{ 1.push(): 在数组末尾添加一个或多个元素,并返回修改后的数组. let fruits = ['apple', 'banana', 'orange']; fruit ...