精华内容
下载资源
问答
  • 与断路器或服务发现之类的事物相比,它既不有趣也不酷,但是它生态系统中至重要的部分,尤其在企业环境中。 我正在为东海岸的一家医疗企业从事大型微服务项目。 我们协助的基础架构的第一部分就是安全性,...

    一范式二范式三范式bc范式

    安全是实现微服务体系结构最不光彩的方面之一。 与断路器或服务发现之类的事物相比,它既不有趣也不酷,但是它是生态系统中至关重要的部分,尤其是在企业环境中。

    我正在为东海岸的一家医疗企业从事大型微服务项目。 我们协助的基础架构的第一部分就是安全性,事实证明,它是所有之后的一切的救命稻草。 我能够看到在微服务环境中哪种安全性很好,哪些不好。 在这篇博客文章中,我将对如何在微服务中实现安全性进行中到高级的探讨。

    安全概述

    首先,安全实际上是什么意思? 大多数企业在安全性的保护下有三个独立的方面:身份验证,授权和访问。

    身份验证回答了以下问题:“此用户是否具有访问系统的有效凭据?”

    授权回答问题“此经过身份验证的用户是否有权执行此操作?”

    Access回答问题“此经过身份验证和授权的用户是否有权在此实体上执行此操作?”

    在此博客文章中,我们将从身份验证开始,然后转到授权,然后从Access结束。

    认证方式

    通常,API网关是验证身份验证和执行授权的最佳场所。 这使您可以确保从边缘到生态系统的所有内容均已正确认证。

    在Java世界中,Spring Security OAuth2的即用型设置将使您设置一个微服务,您可以调用该微服务来获取API令牌。 由于它是OAuth2客户端,因此您的API网关在收到针对OAuth2微服务验证API令牌的请求时,便具有Servlet过滤器。

    在我的客户中,我们不希望每次您访问API网关时都要花费额外的费用来调用身份验证微服务。 因此,相反,我们在部署时为API网关和身份验证微服务注入了秘密加密字符串。 每个环境(DEV,QA等)都有自己的秘密加密字符串。 尽管我不确定如何在Spring Security中进行设置,因为我的客户端是.NET企业,但这对我们来说确实很好。

    身份验证服务生成API令牌时,我们会在其中嵌入用于授权目的的信息。 (有关稍后提供的信息的更多信息。)这具有使我们的API令牌过长的副作用,因此您必须牢记您的应用服务器对HTTP标头长度的默认限制。 这样做的好处是,我们不再需要会话来存储相同的信息,并且借助部署时共享的加密密钥来安全地传输该信息。

    通过将其存储在会话中(我们在职业生涯中都做到了这一点),这使我们免于开发人员一起窃取功能(我们在职业生涯中都做到了),并且由于负载平衡无需担心粘性会话,因此扩展服务非常容易。

    我们还在API令牌中嵌入的一件事是有关它何时过期的信息。 API网关收到令牌后,便对其进行解密,这是授权检查,因为只有授权微服务才能发出该令牌。 然后,我们验证令牌尚未过期。

    这花了我一些时间来适应,但是对于微服务(如我在下面的注释中看到的),有效身份验证要求的注释是level.done在API网关级别而不是在微服务的控制器/方法级别。

    授权书

    您可以选择两种授权方案。 大多数人知道的更多是基于角色的授权 使用此方案,端点定义角色。

    例如: DELETE /user/:userId API端点需要SuperAdministrator角色,而GET /user/favoriteCereal仅需要一个User角色。 如果您的角色很少,并且访问权限很少改变,我会建议您这样做。

    因此,您将存储在API令牌中的信息(JWT适用于那些令牌,而我们的某些其他客户端则使用它们)将是一组角色名称。 Spring Security 开箱即用地支持基于角色的授权

    不幸的是,我们大多数中型和大型客户的角色都是色拉,他们对API的许可会不断变化,如果更改许可要求重新部署JAR,他们会杀死我们。 而是这些客户需要基于声明的授权 (角色定义端点。)

    例如:SystemAdministrator角色为* /user/* ,User GET /user/favoriteCereal

    您将存储在API令牌中的信息将是API网关最容易/最快地消化以决定解密的令牌是否正确执行该调用的信息。

    不幸的是,我不认为这是Spring Security内置的。 为我们实现此功能的时间可能是2017年第三季度或第四季度,所以至少从C#的角度我将了解更多。

    访问

    确认API令牌的授权后,您需要将其传递给您的API网关将要调用的微服务。 这是必需的,以便您可以填充数据库中的字段,例如CreatedByUserID等。 您可以选择将解密的JWT传递给微服务,这可能很好。

    如果要提高安全性,则应在部署时为API网关和微服务注入自己的加密密钥。 这不同于API网关和身份验证微服务所共享的那种。 或保持不变。 这只是公司安全部门认为最好的。

    到目前为止,我所谈到的授权实际上只是与执行API调用有关。 关于回答“发出此请求的实体是否有能力对数据库Y中的记录执行操作X?”的回答,最好的方法是对数据库记录中的访问控制列表(ACL)进行操作。是的

    较大的客户端需要定期旋转SSL证书和密钥。 这可能会导致微服务问题,因为如果在部署时注入加密密钥(如我建议的那样),则需要部署更多的服务。

    您可以进行蓝色/绿色部署,也可以使其成为验证所依据的一系列加密密钥。 您需要在其中一个密钥过期之前重新部署一个月,然后将新密钥首先包含在API网关中。 然后,您将新密钥添加到身份验证微服务。 然后,当旧密钥过期时,您可以先将其从Authentication微服务中删除,然后在宽限期后从API网关中将其删除。 如果您将过期时间嵌入令牌中,则宽限期至少应为该长度。

    使用API​​令牌需要考虑的最后一件事是如何处理到期时间。 微软的策略是实质上发行两个令牌:API令牌和Refresh令牌。

    API令牌是我在本博客中一直在谈论的内容,用于对API执行操作。

    刷新令牌只能用于获取新的API令牌,而不必与身份验证微服务重新进行身份验证。 如果您的API令牌每20分钟失效一次,并且您不希望最终用户每次都再次输入密码,此功能将非常有用。 刷新令牌的到期时间通常是API令牌的到期时间的2倍或3倍。

    最后的想法

    最后,对于安全性方面的所有事情,请确保团队编写的代码量最少,并且可以从防弹库利用的代码量最大化。 安全性至关重要,在大多数情况下,您都希望信任从事安全性业务的公司编写的代码。

    翻译自: https://www.javacodegeeks.com/2017/03/security-microservices-paradigm.html

    一范式二范式三范式bc范式

    展开全文
  • 在商用厨房中,选择适合的厨房设备重要的,毕竟厨房关系到每一个人的健康安全。不过,市面上厨房设备花样频出,很多人对于厨房设备,可真的挑花了眼,还不知道到底该选一家的产品。小编今天来给小伙伴介绍...

    a3673ebda4148171e2e9ea1498e8ffa0.gif

    4e124c83d8b3986efc0a1dc068e12e5d.gif

    29bb406744d01a5cbd2071105b7f5c9c.pngb1a3ef08fed3073e827be9416e19c7dc.png

    一个酒店,一个学校食堂,一个医院等地方建立的时候,肯定会设计并建造商用厨房。

    b1a3ef08fed3073e827be9416e19c7dc.png

    921a755e688318e0d1016554c1a40fd2.png

    在商用厨房中,选择适合的厨房设备是至关重要的,毕竟厨房关系到每一个人的健康安全。

    不过,市面上厨房设备花样频出,很多人对于厨房设备,可真的是挑花了眼,还不知道到底该选哪一家的产品。

    小编今天来给小伙伴介绍一个选择厨房设备,你应该去注意和关心的三个标准。

    7f907d40ddb9f4e66a16d138b2639611.png

    1.性能价格成正比

    选择商用厨房设备的时候,我们一般都会把注意力放在,各种技术指标是否与铭牌上所写的一致,是不是能达到要求。其实,除了这些,我们最应该看重的是指标维持长短。

    如果说,指标很好,我们花了不少钱买了回去,结果用个一年半载,厨房设备的寿命就不好了,这不就是个亏本的买卖吗?

    只有让性能与价格成正比,才是成功的选择。

    2.成本费用多方面考虑

    说到费用,我们当中的绝大多数人都是考虑厨房设备的价格,这其实是不全面的。

    成本费用我们需要多方面去考虑,一般可以考虑:设备价格、安装费用、运费、保险和包装费用、修理费用、经营成本等。

    只有所有费用都考虑周全,后期使用厨房设备的时候,才不会有后患。

    3.卫生与安全有保障

    除了性能与价格,选择厨房设备,卫生与安全也是重要的考核标准之一。

    商用厨房设备使用,要考虑操作人员使用是否是安全的。当然,为了防止各种意外的发生,我们需要去设置一些保护装置,比如:自动断电、自动停机、自动报警和接地线等。

    卫生不用多说,不管是酒店、医院,还是学校,都是人来人往的。如果一旦发生卫生事故,后果是难以预料的。

    所以,在选择厨房设备的时候,就需要考虑设备的材质问题,比如:炊事机械应该用不发生毒性迁移的材料制成,内壁应该用不锈钢板制成,设备内壁不可以使用镀锌板或刷漆........

    801710437b3a4036e8c6b377f0f2bb7a.gif

    0c9601b57af6fd031426124a2ba655a4.png

    展开全文
  • 冬季危化品运输车自救逃生知识点篇 日前,各地在开展冬季危化品运输集中排查整治,严把安全关。冬季降雪路面湿滑结冰,增加了危化品运输车的行驶风险,容易出现打滑等现象。作为普通民众,在路上遇到危化品运输车...
  • 日前,国内动力电池行业...电动汽车的发展需要更好的电池,动力蓄电池的比能量、寿命、安全性和价格,对纯电驱动汽车的发展至重要。其中具有比能量高、寿命长等优点的目前实用价值的电动汽车电池,在混合动力汽车、
  • 这篇文章主要介绍了PE文件基础知识及恶意样本检测的种处理知识,手动编写代码实现了提取IAT表、二进制转字符串及获取PE文件时间戳,这恶意样本分析和溯源至重要的基础,并且网络上还没见到同时涵盖这个功能...

    系统安全绕不开PE文件,PE文件又与恶意样本检测及分析紧密相关。前文作者带领大家逆向分析两个CrackMe程序,包括逆向分析和源码还原。这篇文章主要介绍了PE文件基础知识及恶意样本检测的三种处理知识,手动编写代码实现了提取IAT表、二进制转字符串及获取PE文件时间戳,这是恶意样本分析和溯源至关重要的基础,并且网络上还没见到同时涵盖这三个功能且详细的文章,希望对您有所帮助。术路上哪有享乐,为了提升安全能力,别抱怨,干就对了~

    同时,PE文件基础知识推荐作者另一个安全系列:


    从2019年7月开始,我来到了一个陌生的专业——网络空间安全。初入安全领域,是非常痛苦和难受的,要学的东西太多、涉及面太广,但好在自己通过分享100篇“网络安全自学”系列文章,艰难前行着。感恩这一年相识、相知、相趣的安全大佬和朋友们,如果写得不好或不足之处,还请大家海涵!

    接下来我将开启新的安全系列,叫“安全攻防进阶篇”,也是免费的100篇文章,作者将更加深入的去研究恶意样本分析、逆向分析、内网渗透、网络攻防实战等,也将通过在线笔记和实践操作的形式分享与博友们学习,希望能与您一起进步,加油~

    话不多说,让我们开始新的征程吧!您的点赞、评论、收藏将是对我最大的支持,感恩安全路上一路前行,如果有写得不好或侵权的地方,可以联系我删除。基础性文章,希望对您有所帮助,作者目的是与安全人共同进步,加油~

    作者的github资源:
    软件安全:https://github.com/eastmountyxz/Software-Security-Course
    其他工具:https://github.com/eastmountyxz/NetworkSecuritySelf-study
    Windows-Hacker:https://github.com/eastmountyxz/PE-InfoGet


    声明:本人坚决反对利用教学方法进行犯罪的行为,一切犯罪行为必将受到严惩,绿色网络需要我们共同维护,更推荐大家了解它们背后的原理,更好地进行防护。(参考文献见后)

    前文回顾:
    [安全攻防进阶篇] 一.什么是逆向分析、逆向分析应用及经典扫雷游戏逆向
    [安全攻防进阶篇] 二.如何学好逆向分析、逆向路线推荐及吕布传游戏逆向案例
    [安全攻防进阶篇] 三.OllyDbg和Cheat Engine工具逆向分析植物大战僵尸游戏
    [安全攻防进阶篇] 四.逆向分析之条件语句和循环语句源码还原及流程控制逆向
    [安全攻防进阶篇] 五.逆向分析之Win32 API获取及加解密目录文件、OllyDbg逆向其原理
    [安全攻防进阶篇] 六.逆向分析之OllyDbg逆向CrackMe01-02及加壳判断



    一.PE文件

    1.PE文件基础

    什么是PE文件?
    PE文件的全称是Portable Executable,意为可移植的可执行的文件,常见的EXE、DLL、OCX、SYS、COM都是PE文件,PE文件是微软Windows操作系统上的程序文件(可能是间接被执行,如DLL)。

    EXE文件格式:

    • DOS:MZ格式
    • WIndows 3.0/3.1:NE(New Executable)、16位Windows可执行文件格式

    为什么要重点学习这种文件格式呢?

    • PE文件是可移植、可执行、跨Win32平台的文件格式
    • 所有Win32执行体(exe、dll、kernel mode drivers)
    • 知道PE文件本质后,能更好进行恶意样本分析、APT攻击分析、勒索病毒分析
    • 了解软件加密和加壳的思想,能够PJ相关的PE文件
    • 它是您熟悉Windows操作系统的第一步,包括EXE程序怎么映射到内存,DLL怎么导入等
    • 软件逆向工程的基本思想与PE文件格式息息相关
    • 如果您想成为一名黑客、系统安全工程师,那么精通PE文件是非常必要的

    可执行程序是具有不同的形态的,比如用户眼中的QQ如下图所示。

    在这里插入图片描述

    本质上,QQ如下图所示。

    在这里插入图片描述


    PE文件格式总体结构
    接着让我们来欣赏下PE文件格式总体结构图,包括:MZ头部、DOS stub、PE文件头、可选文件头、节表、节等。

    在这里插入图片描述

    本文的第二部分我们将对PE文件格式进行详细解析。比如,MZ头文件是定位PE文件头开始位置,用于PE文件合法性检测。DOS下运行该程序时,会提示用户“This Program cannot be run in DOS mode”。

    在这里插入图片描述

    PE文件格式与恶意软件的关系

    • 何为文件感染或控制权获取?
      使目标PE文件具备或启动病毒功能(或目标程序)
      不破坏目标PE文件原有功能和外在形态(如图标)等
    • 病毒代码如何与目标PE文件融为一体呢?
      代码植入
      控制权获取
      图标更改
      Hook

    PE文件解析常用工具包括:

    • PEView:可按照PE文件格式对目标文件的各字段进行详细解析。
    • Stud_PE:可按照PE文件格式对目标文件的各字段进行详细解析。
    • Ollydbg:可跟踪目标程序的执行过程,属于用户态调试工具。
    • UltraEdit \ 010Editor:可对目标文件进行16进制查看和修改。


    2.PE文件格式解析

    我们通过010Editor观察PE文件例子程序hello-2.5.exe的16进制数据,详细讲解PE文件格式。PE文件结构如下图所示,推荐大家使用010Editor工具及其模板来进行PE文件分析。

    MZ头部+DOS stub+PE文件头+可选文件头+节表+节

    在这里插入图片描述


    (1) 使用010Editor工具打开PE文件,并运行模板。
    该PE文件可分为若干结构,如下图所示。

    在这里插入图片描述


    (2) MZ文件头(000h-03fh)。
    下图为hello-2.5.exe的MZ文件头,该部分固定大小为40H个字节。偏移3cH处字段Offset to New EXE Header,指示“NT映象头的偏移地址”,其中000000B0是NT映象头的文件偏移地址,定位PE文件头开始位置,用于PE文件合法性检验。

    在这里插入图片描述

    000000B0指向PE文件头开始位置。

    在这里插入图片描述


    (3) DOS插桩程序(040h-0afh)
    DOS Stub部分大小不固定,位于MZ文件头和NT映象头之间,可由MZ文件头中的Offset to New EXE Header字段确定。下图为hello-2.5.exe中的该部分内容。

    在这里插入图片描述


    (4) PE文件头(0b0h-1a7h)
    该部分包括PE标识、映像文件头、可选文件头。

    • Signature:字串“PE\0\0”,4个字节(0b0H~0b4H)
    • 映象文件头File Header:14H个字节(0b5H~0c7H)
      偏移2H处,字段Number of Section 给出节的个数(2个字节):0003
      偏移10H处,字段Size of Optional Header 给出可选映象头的大小(2个字节):00E0
    • 可选映象头Optional Header:0c8H~1a7H

    在这里插入图片描述

    对应解析如下图所示,包括PE标识、X86架构、3个节、文件生成时间、COFF便宜、可选头大小、文件信息标记等。

    在这里插入图片描述

    010Editor使用模板定位PE文件各节点信息。

    在这里插入图片描述

    PE文件可选文件头224字节,其对应的字段信息如下所示:

    typedef struct _IMAGE_OPTIONAL_HEADER {
    
        WORD    Magic;                  /*机器型号,判断是PE是32位还是64位*/
        BYTE    MajorLinkerVersion;          /*连接器版本号高版本*/
        BYTE    MinorLinkerVersion;          /*连接器版本号低版本,组合起来就是 5.12 其中5是高版本,C是低版本*/
        DWORD   SizeOfCode;               /*代码节的总大小(512为一个磁盘扇区)*/
        DWORD   SizeOfInitializedData;        /*初始化数据的节的总大小,也就是.data*/
        DWORD   SizeOfUninitializedData;       /*未初始化数据的节的大小,也就是 .data ? */
        DWORD   AddressOfEntryPoint;          /*程序执行入口(OEP) RVA(相对偏移)*/
        DWORD   BaseOfCode;               /*代码的节的起始RVA(相对偏移)也就是代码区的偏移,偏移+模块首地址定位代码区*/
        DWORD   BaseOfData;               /*数据结的起始偏移(RVA),同上*/
        DWORD   ImageBase;               /*程序的建议模块基址(意思就是说作参考用的,模块地址在哪里)*/
    
        DWORD   SectionAlignment;           /*内存中的节对齐*/
        DWORD   FileAlignment;             /*文件中的节对齐*/
        WORD    MajorOperatingSystemVersion;    /*操作系统版本号高位*/
        WORD    MinorOperatingSystemVersion;    /*操作系统版本号低位*/
        WORD    MajorImageVersion;          /*PE版本号高位*/
        WORD    MinorImageVersion;          /*PE版本号低位*/
        WORD    MajorSubsystemVersion;        /*子系统版本号高位*/
        WORD    MinorSubsystemVersion;        /*子系统版本号低位*/
        DWORD   Win32VersionValue;          /*32位系统版本号值,注意只能修改为4 5 6表示操作系统支持nt4.0 以上,5的话依次类推*/
        DWORD   SizeOfImage;               /*整个程序在内存中占用的空间(PE映尺寸)*/
        DWORD   SizeOfHeaders;            /*所有头(头的结构体大小)+节表的大小*/
        DWORD   CheckSum;               /*校验和,对于驱动程序,可能会使用*/
        WORD    Subsystem;              /*文件的子系统 :重要*/
        WORD    DllCharacteristics;         /*DLL文件属性,也可以成为特性,可能DLL文件可以当做驱动程序使用*/
        DWORD   SizeOfStackReserve;         /*预留的栈的大小*/
        DWORD   SizeOfStackCommit;          /*立即申请的栈的大小(分页为单位)*/
        DWORD   SizeOfHeapReserve;          /*预留的堆空间大小*/
        DWORD   SizeOfHeapCommit;           /*立即申请的堆的空间的大小*/
        DWORD   LoaderFlags;             /*与调试有关*/
        DWORD   NumberOfRvaAndSizes;         /*下面的成员,数据目录结构的项目数量*/
        IMAGE_DATA_DIRECTORY DataDirectory[16];  /*数据目录,默认16个,16是宏,这里方便直接写成16*/
    } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
    

    (5) 节表(1a8h-21fh)

    • 表项大小固定,28H个字节;表项个数由映象文件头的字段Number of Section 给出。
    • 每个表项的起始位置起(8个字节),字段Name给出对应节的名称。
    • 每个表项的偏移14H处(4个字节),字段Offset to Raw Data给出对应节的起始文件偏移。

    在这里插入图片描述

    该结构包括3个节,对应上图的3个struct IMAGE_SECTION_HEADER,即“.test”、“.rdata”、“.data”节,其偏移地址对应下图紫色区域,分别是400、600、800的位置。

    在这里插入图片描述


    (6) 3个节

    • 400H-5ffH:代码节
    • 600H-7ffH:引入函数节
    • 800H-9ffH:数据节

    在这里插入图片描述

    注意,代码节“.text”前46H为数据,后面全是0位填充值,为了实现文件的200H对齐,所以代码节是400H到5ffH。

    在这里插入图片描述


    (7) 引入函数节
    ⽤来从其他DLL中引⼊函数,引入了kernel32.dll和user32.dll,这个节一般名为“.rdata”。引入函数是被某模块调用的但又不在调用者模块中的函数,用来从其他(系统或第三方写的)DLL中引入函数,例如kernel32.dll、gdi32.dll等。

    在这里插入图片描述

    010Editor打开如下图所示:

    在这里插入图片描述

    详细标注信息如下图所示:(图引自HYQ同学,再此感谢)

    在这里插入图片描述


    (8) 数据节
    数据节实际大小58h,对齐后大小200h,地址为800h-9ffh,包括对话框弹出的具体内容。

    在这里插入图片描述



    二.编写代码提取IAT表

    IAT的全称是Import Address Table,导入地址表。 IAT表是执行程序或者DLL为了实现动态加载和重定位函数地址,用到的一个导入函数地址表,这里面记录了每个导入函数的名字和所在的DLL名称。在PE加载的时候系统会加载这些DLL到用户的地址空间然后把函数地址覆盖这个表里的函数地址,然后重构所有用到这个表的代码,让其调用直接指向实际函数地址,PE的IAT表会留在内存,其中导入地址表就指示函数实际地址。


    首先,我们通过Stud_PE软件打开我们的hello-2.5.exe,发现它调用了两个DLL和两个函数。

    • kernel32.dll:ExitProcess
    • user32.dll:MessageBoxA

    在这里插入图片描述

    同样的方法我们打开恶意样本就可以发现它加载的DLL文件及IAT表内容,如下图所示的网络函数及进程、文件操作,包括对应的地址和名称。

    在这里插入图片描述

    在这里插入图片描述


    第二步,我们打开VS或VC++,新建工程添加main.cpp函数。编写代码如下,它将实现一个自动提取IAT表名称的功能。

    #include <windows.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <Dbghelp.h>
    
    void ReadNTPEInfo(PIMAGE_NT_HEADERS pImageNtPE);
    ULONG RvaToOffset(IMAGE_NT_HEADERS* pNtHeader, ULONG Rva);
    
    #define pNtHeaders pImageNtHeaders
    
    int main()
    {
        //PE文件名称
        char file[] = "hello-2.5.exe";
        char name[] = "test";
    
        //DOS头
        PIMAGE_DOS_HEADER pImageDosHeader;
        //NT头(包括PE标识+Image_File_Header+OptionHeader)
        PIMAGE_NT_HEADERS pImageNtHeaders;
        //标准PE头、
        PIMAGE_FILE_HEADER pImageFileHeader;
        //扩展PE头
        IMAGE_OPTIONAL_HEADER32 pImageOptionHeaders;
        HANDLE hFile;
        HANDLE hMapObject;
        //DOS头
        PUCHAR uFileMap;
    
        hFile = CreateFile(file, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
        if (hFile == NULL)
        {
            printf("打开文件失败\n");
            system("pause");
            return 0;
        }
    
        hMapObject = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
        if (hMapObject == NULL)
        {
            printf("创建文件映射内核对对象失败\n");
            system("pause");
            return 0;
        }
    
        //PE基址
        uFileMap = (PUCHAR)MapViewOfFile(hMapObject, FILE_MAP_READ, 0, 0, 0);
        if (uFileMap == NULL)
        {
            printf("映射到进程地址空间失败\n");
            system("pause");
            return 0;
        }
    
        pImageDosHeader = (PIMAGE_DOS_HEADER)uFileMap;
        if (pImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
        {
            printf("不是PE结构\n");
            system("pause");
            return 0;
        }
    
        //定位到NT PE头
        pImageNtHeaders = (PIMAGE_NT_HEADERS)((PUCHAR)uFileMap + pImageDosHeader->e_lfanew);
        //导入表的相对虚拟地址(RVA)
        ULONG rva_ofimporttable = pImageNtHeaders->OptionalHeader.DataDirectory[1].VirtualAddress;
        //根据相对虚拟(rva)地址计算偏移地址(offset)
        ULONG offset_importtable = RvaToOffset(pImageNtHeaders, rva_ofimporttable);
        if (!offset_importtable)
        {
            printf("获取导入表偏移地址失败\n");
            system("pause");
            return 0;
        }
    
        PIMAGE_THUNK_DATA s;
    
        //取得导入表的地址
        IMAGE_IMPORT_DESCRIPTOR* pImportTable = (IMAGE_IMPORT_DESCRIPTOR*)((char*)uFileMap + offset_importtable);
    
        IMAGE_IMPORT_DESCRIPTOR null_iid;
        IMAGE_THUNK_DATA null_thunk;
        memset(&null_iid, 0, sizeof(null_iid));
        memset(&null_thunk, 0, sizeof(null_thunk));
    
        //每个元素代表了一个引入的DLL。
        for (int i = 0; memcmp(pImportTable + i, &null_iid, sizeof(null_iid)) != 0; i++)
        {
            //获取DLL名称
            char* dllName = (char*)(uFileMap + RvaToOffset(pImageNtHeaders, pImportTable[i].Name));
            printf("模块[%d]: %s\n", i, (char*)dllName);
            printf("%s\n", (char*)dllName);
            
            PIMAGE_THUNK_DATA32 pThunk = (PIMAGE_THUNK_DATA32)(uFileMap + RvaToOffset(pImageNtHeaders, pImportTable[i].FirstThunk));
    
            while (pThunk->u1.Ordinal != NULL)
            {
                PIMAGE_IMPORT_BY_NAME pname = (PIMAGE_IMPORT_BY_NAME)(uFileMap + RvaToOffset(pImageNtHeaders, pThunk->u1.AddressOfData));
                printf("函数编号: %d 名称: %s\n", pname->Hint, pname->Name);
    
                //文件名称 DLL名称 函数名称 组织名称
                //printf("%s,%s,%s,%s\n", file, (char*)dllName, pname->Name, name);
                pThunk++;
            }
            printf("\n");
        }
        system("pause");
        return 0;
    }
    
    //读取PE文件信息
    void ReadNTPEInfo(PIMAGE_NT_HEADERS pImageNtPE)
    {
        printf("运行平台:   0x%04X\n", pImageNtPE->FileHeader.Machine);
        printf("节数量:   %d\n", pImageNtPE->FileHeader.NumberOfSections);
        printf("PE属性:   0x%04X\n", pImageNtPE->FileHeader.Characteristics);
    }
    
    //计算Offset
    ULONG RvaToOffset(IMAGE_NT_HEADERS* pNtHeader, ULONG Rva)
    {
        //PE节
        IMAGE_SECTION_HEADER* p_section_header;
        ULONG sNum, i;
        //取得节表项数目
        sNum = pNtHeader->FileHeader.NumberOfSections;
        //取得第一个节表项
        p_section_header = (IMAGE_SECTION_HEADER*)
            ((BYTE*)pNtHeader + sizeof(IMAGE_NT_HEADERS));
        for (i = 0; i < sNum; i++)
        {
            //printf("PE 节名称: %s\n",p_section_header->Name);
            if ((p_section_header->VirtualAddress <= Rva) && Rva < (p_section_header->VirtualAddress + p_section_header->SizeOfRawData))
            {
                return Rva - p_section_header->VirtualAddress + p_section_header->PointerToRawData;
            }
            p_section_header++;
        }
        return 0;
    }
    

    输出结果如下图所示:

    在这里插入图片描述


    同样的方法我们可以获取恶意样本的IAT表,如下图所示:

    模块[0]: msvcrt.dll
    msvcrt.dll
    函数编号: 221 名称: _controlfp
    函数编号: 158 名称: __set_app_type
    函数编号: 746 名称: memcpy
    函数编号: 138 名称: __p__fmode
    函数编号: 133 名称: __p__commode
    函数编号: 189 名称: _adjust_fdiv
    函数编号: 160 名称: __setusermatherr
    函数编号: 322 名称: _initterm
    函数编号: 170 名称: __wgetmainargs
    函数编号: 560 名称: _wcmdln
    函数编号: 668 名称: exit
    函数编号: 207 名称: _cexit
    函数编号: 79 名称: _XcptFilter
    函数编号: 253 名称: _exit
    函数编号: 204 名称: _c_exit
    函数编号: 740 名称: malloc
    函数编号: 244 名称: _except_handler3
    函数编号: 748 名称: memset
    
    模块[1]: urlmon.dll
    urlmon.dll
    函数编号: 113 名称: UrlMkGetSessionOption
    
    模块[2]: WININET.dll
    WININET.dll
    函数编号: 154 名称: InternetOpenW
    函数编号: 105 名称: InternetCheckConnectionW
    函数编号: 159 名称: InternetReadFile
    函数编号: 107 名称: InternetCloseHandle
    函数编号: 153 名称: InternetOpenUrlW
    
    模块[3]: KERNEL32.dll
    KERNEL32.dll
    函数编号: 449 名称: GetCurrentProcessId
    函数编号: 453 名称: GetCurrentThreadId
    函数编号: 659 名称: GetTickCount
    函数编号: 935 名称: QueryPerformanceCounter
    函数编号: 1189 名称: SetUnhandledExceptionFilter
    函数编号: 1235 名称: UnhandledExceptionFilter
    函数编号: 1216 名称: TerminateProcess
    函数编号: 611 名称: GetStartupInfoW
    函数编号: 1273 名称: WaitForSingleObject
    函数编号: 181 名称: CreateThread
    函数编号: 448 名称: GetCurrentProcess
    函数编号: 1258 名称: VirtualAllocEx
    函数编号: 1202 名称: Sleep
    函数编号: 633 名称: GetSystemTimeAsFileTime.
    

    该部分代码参考看雪SuperProgram师傅文章,非常感谢。


    第三步,为什么要实现这个功能呢?其它工具不是都有类似的功能了。
    首先,在线沙箱在分析恶意代码时,它们也会从IAT表这个角度进行分析。其操作比较简单,就是将恶意样本上传至指定在想网址即可。

    我们以 virustotal沙箱为例,打开主页如下图所示,点击“choose file”,上传我们的勒索exe文件。

    在这里插入图片描述

    结果从72个在线引擎中扫描出4个是恶意样本的引擎,如下图所示:

    在这里插入图片描述

    我们可以看到该样本的基本信息,包括MD5、SHA-1、文件历史信息、PE文件节点信息。其中关注的重点是该文件的导入函数信息,在Imports中显示,主要包括:

    • KERNEL32.dll
    • VCRUNTIME140D.dll
    • ucrtbased.dll

    在这里插入图片描述

    ucrtbased.dll主要包括的文件操作如下图所示,比如fopen、fputc、system、rename等函数。

    在这里插入图片描述

    其次,当我们要分析海量样本,从中提取其关联性时,是需要编写代码实现自动提取特征,再进行分析的,所以本部分实现了一个C++代码提取IAT表的技术,希望对您有所帮助。当获取各个APT组织的函数调用信息,才能进一步挖掘它们的特征及习惯。

    在这里插入图片描述



    三.二进制PE文件转字符串

    下面分享如何将二进制文件转换成十六进制,再转换成字符串的过程。这里作者真心请教大家两个问题:

    • 如果自动获取PE文件中定义的字符串呢?
    • 如果自动转换成对应的源代码呢?
    • 如何自动提取每部分功能对应的核心代码呢?

    在这里插入图片描述

    代码如下:

    import os
    import binascii
    
    #-----------------------------------定义转换函数-----------------------------------
    def str_to_hex(s):
        return r"\x"+r'\x'.join([hex(ord(c)).replace('0x', '') for c in s])
    
    def hex_to_str(s):
        return ''.join([chr(i) for i in [int(b, 16) for b in s.split(r'\x')[1:]]])
        
    def str_to_bin(s):
        return ' '.join([bin(ord(c)).replace('0b', '') for c in s])
        
    def bin_to_str(s):
        return ''.join([chr(i) for i in [int(b, 2) for b in s.split(' ')]])
    
    
    #--------------------------------二进制转字节码---------------------------------
    fileIn = 'hello-2.5.exe'
    fileOut = 'hex-hello'
    inp = open(fileIn,'rb')
    outp = open(fileOut,'w')
    
    i = 0
    for c in inp.read():
        outp.write('\\%#04x' %(c))
        i += 1
        if i >= 16:
            outp.write('\n')
            i = 0
    inp.close()
    outp.close()
    print('二进制换十六进制成功\n')
    
        
    """
    a="abcdefg"
    x=str_to_hex(a)
    print(x)
    print(hex_to_str(x))
    """
    
    #--------------------------------字节码转换字符串--------------------------------
    #decode():bytes编码转为str
    #encode():str编码转为bytes
    f = open('hex-hello', 'r')
    outp = open("result-hello.txt",'w', encoding="utf-8")
    for n in f.readlines():
        n = n.strip()
        txt = n.replace('\\0x','\\x')
        res = hex_to_str(txt)
        outp.write(res + '\n')
    outp.close()
    print('十六进制转字符串成功\n')
    

    如果我们直接打开一个EXE文件,发现它显示如下图所示的内容:

    在这里插入图片描述

    当我们转换成16进制和字符串后,它变成了如下图所示的内容。字符串勉强还能进行下一步和自然语言处理结合的分析,但更详细的分析需要和PE文件结构结合。

    在这里插入图片描述

    在这里插入图片描述

    如果我们使用IDA、010editor类似软件打开,它能够更清晰地对比各部分内容。

    在这里插入图片描述


    四.自动提取PE文件时间戳

    接着我们尝试通过Python来获取时间戳,python的PE库是pefile,它是用来专门解析PE文件的,可静态分析PE文件。

    第一步,我们通过010Editor分析PE文件。
    其时间戳的输出结果如下:

    • 06/19/2020 10:46:21

    我们希望通过Python写代码实现自动化提取,为后续自动化溯源提供帮助。

    在这里插入图片描述

    第二步,撰写Python代码实现简单分析。

    import pefile
    import os,string,shutil,re
    
    PEfile_Path = "MFCApplication.exe"
     
    pe = pefile.PE(PEfile_Path)
    print(type(pe))
    print(pe)
    

    输出如下图所示结果,这是Python包自定义的PE结构。

    在这里插入图片描述

    squeezed text表示python的一种编程规范要求,简称pep8,你只需要将鼠标放到Squeezed上,右键Copy即可查看内容,显示的是该PE文件的基本结构。如下所示,与010Editor分析的结果前后是一致的。

    ----------DOS_HEADER----------
    
    [IMAGE_DOS_HEADER]
    0x0        0x0   e_magic:                       0x5A4D    
    0x2        0x2   e_cblp:                        0x90      
    0x4        0x4   e_cp:                          0x3       
    0x6        0x6   e_crlc:                        0x0       
    0x8        0x8   e_cparhdr:                     0x4       
    0xA        0xA   e_minalloc:                    0x0       
    0xC        0xC   e_maxalloc:                    0xFFFF    
    0xE        0xE   e_ss:                          0x0       
    0x10       0x10  e_sp:                          0xB8      
    0x12       0x12  e_csum:                        0x0       
    0x14       0x14  e_ip:                          0x0       
    0x16       0x16  e_cs:                          0x0       
    0x18       0x18  e_lfarlc:                      0x40      
    0x1A       0x1A  e_ovno:                        0x0       
    0x1C       0x1C  e_res:                         
    0x24       0x24  e_oemid:                       0x0       
    0x26       0x26  e_oeminfo:                     0x0       
    0x28       0x28  e_res2:                        
    0x3C       0x3C  e_lfanew:                      0x108     
    
    ----------NT_HEADERS----------
    
    [IMAGE_NT_HEADERS]
    0x108      0x0   Signature:                     0x4550    
    
    ----------FILE_HEADER----------
    
    [IMAGE_FILE_HEADER]
    0x10C      0x0   Machine:                       0x14C     
    0x10E      0x2   NumberOfSections:              0xA       
    0x110      0x4   TimeDateStamp:                 0x5EEC977D [Fri Jun 19 10:46:21 2020 UTC]
    0x114      0x8   PointerToSymbolTable:          0x0       
    0x118      0xC   NumberOfSymbols:               0x0       
    0x11C      0x10  SizeOfOptionalHeader:          0xE0      
    0x11E      0x12  Characteristics:               0x102     
    Flags: IMAGE_FILE_32BIT_MACHINE, IMAGE_FILE_EXECUTABLE_IMAGE
    
    ----------OPTIONAL_HEADER----------
    
    [IMAGE_OPTIONAL_HEADER]
    0x120      0x0   Magic:                         0x10B     
    0x122      0x2   MajorLinkerVersion:            0xE       
    0x123      0x3   MinorLinkerVersion:            0x1A      
    0x124      0x4   SizeOfCode:                    0x700C00  
    0x128      0x8   SizeOfInitializedData:         0x2F1E00  
    0x12C      0xC   SizeOfUninitializedData:       0x0       
    0x130      0x10  AddressOfEntryPoint:           0x36CE65  
    0x134      0x14  BaseOfCode:                    0x1000    
    0x138      0x18  BaseOfData:                    0x1000    
    0x13C      0x1C  ImageBase:                     0x400000  
    ....
    
    ----------PE Sections----------
    
    [IMAGE_SECTION_HEADER]
    0x200      0x0   Name:                          .textbss
    0x208      0x8   Misc:                          0x35B30B  
    0x208      0x8   Misc_PhysicalAddress:          0x35B30B  
    0x208      0x8   Misc_VirtualSize:              0x35B30B  
    0x20C      0xC   VirtualAddress:                0x1000    
    0x210      0x10  SizeOfRawData:                 0x0       
    ....
    

    第三步,注意这里同样可以通过Python获取IAT表相关信息。

    import pefile
    import os,string,shutil,re
    
    PEfile_Path = "MFCApplication.exe"
    
    #解析PE文件
    pe = pefile.PE(PEfile_Path)
    print(type(pe))
    print(pe)
    
    #获取导入表信息
    for item in pe.DIRECTORY_ENTRY_IMPORT:
        print(item.dll)
        for con in item.imports:
            print(con.name)
        print("") #换行
    

    输出如下所示的结果,包括KERNEL32.dll、USER32.dll等。

    b'KERNEL32.dll'
    b'RtlUnwind'
    b'GetModuleHandleExW'
    b'GetCommandLineA'
    b'GetSystemInfo'
    b'CreateThread'
    ...
    
    b'USER32.dll'
    b'DlgDirSelectExA'
    b'FindWindowExA'
    b'FindWindowA'
    b'SetParent'
    b'ChildWindowFromPointEx'
    ...
    

    对应010editor的PE软件分析结果如下:

    在这里插入图片描述


    第四步,获取PE时间。通过pe.DOS_HEADER、pe.FILE_HEADER和正则表达式等方法获取对应的内容。

    import pefile
    import os,string,shutil,re
    
    PEfile_Path = "MFCApplication.exe"
    
    #解析PE文件
    pe = pefile.PE(PEfile_Path, fast_load=True)
    print(type(pe))
    print(pe)
    print(pe.get_imphash())
    
    #显示DOS_HEADER
    dh = pe.DOS_HEADER
    
    #显示NT_HEADERS
    nh = pe.NT_HEADERS
    
    #显示FILE_HEADER
    fh = pe.FILE_HEADER
    
    #显示OPTIONAL_HEADER
    oh = pe.OPTIONAL_HEADER
    
    print(type(fh)) #<class 'pefile.Structure'>
    print(str(fh))
    
    #通过正则表达式获取时间
    p = re.compile(r'[[](.*?)[]]', re.I|re.S|re.M)   #最小匹配
    res = re.findall(p, str(fh))
    print(res[1])                                    #第一个值是IMAGE_FILE_HEADER
    # Fri Jun 19 10:46:21 2020 UTC
    

    最终输出结果如下所示,这样我们就完成了Python自动化提取PE软件的时间戳过程。任何一个PE软件都能进行提取,该时间戳也记录了软件的编译时间。

    <class 'pefile.PE'>
    Squeezed text(347 lines).
    
    <class 'pefile.Structure'>
    [IMAGE_FILE_HEADER]
    0x10C      0x0   Machine:                       0x14C     
    0x10E      0x2   NumberOfSections:              0xA       
    0x110      0x4   TimeDateStamp:                 0x5EEC977D [Fri Jun 19 10:46:21 2020 UTC]
    0x114      0x8   PointerToSymbolTable:          0x0       
    0x118      0xC   NumberOfSymbols:               0x0       
    0x11C      0x10  SizeOfOptionalHeader:          0xE0      
    0x11E      0x12  Characteristics:               0x102     
    
    Fri Jun 19 10:46:21 2020 UTC
    

    为什么要进行这样的时间戳分析呢?
    在过去的四年中,安天的工程师们关注到了中国的机构和用户反复遭遇来自“西南方向”的网络入侵尝试。这些攻击虽进行了一些掩盖和伪装,我们依然可以将其推理回原点——来自南亚次大陆的某个国家。他们是怎么做的呢?

    安天通过对样本集的时间戳、时区分析进行分析,发现其来自南亚。样本时间戳是一个十六进制的数据,存储在PE文件头里,该值一般由编译器在开发者创建可执行文件时自动生成,时间单位细化到秒,通常可以认为该值为样本生成时间(GMT时间)。

    在这里插入图片描述

    时间戳的分析需要收集所有可用的可执行文件时间戳,并剔除过早的和明显人为修改的时间,再将其根据特定标准分组统计,如每周的天或小时,并以图形的形式体现,下图是通过小时分组统计结果:

    在这里插入图片描述

    从上图的统计结果来看,如果假设攻击者的工作时间是早上八九点至下午五六点的话,那么将工作时间匹配到一个来自UTC+4或UTC+5时区的攻击者的工作时间。根据我们匹配的攻击者所在时区(UTC+4 或UTC+5),再对照世界时区分布图,就可以来推断攻击者所在的区域或国家。

    在这里插入图片描述

    所以当我们受到持续攻击,并且样本存在相似性的时候,就可以通过这种方法简单溯源其攻击地区来源。当然该方法比较粗,您需要进一步结合样本特征深入分析。

    最终代码:

    import pefile
    import time
    import warnings
    import datetime
    import os,string,shutil,re
    
    #忽略警告
    warnings.filterwarnings("ignore")
    
    PEfile_Path = "MFCApplication.exe"
    
    #----------------------------------第一步 解析PE文件-------------------------------
    pe = pefile.PE(PEfile_Path, fast_load=True)
    print(type(pe))
    print(pe)
    print(pe.get_imphash())
    
    #显示DOS_HEADER
    dh = pe.DOS_HEADER
    
    #显示NT_HEADERS
    nh = pe.NT_HEADERS
    
    #显示FILE_HEADER
    fh = pe.FILE_HEADER
    
    #显示OPTIONAL_HEADER
    oh = pe.OPTIONAL_HEADER
    
    print(type(fh)) #<class 'pefile.Structure'>
    print(str(fh))
    
    #----------------------------------第二步 获取UTC时间-------------------------------
    #通过正则表达式获取时间
    p = re.compile(r'[[](.*?)[]]', re.I|re.S|re.M)   #最小匹配
    res = re.findall(p, str(fh))
    print(res[1])                                    #第一个值是IMAGE_FILE_HEADER
    res_time = res[1].replace(" UTC","")
    # Fri Jun 19 10:46:21 2020 UTC
    
    #获取当前时间
    t = time.ctime()
    print(t,"\n")                                    # Thu Jul 16 20:42:18 2020
    utc_time = datetime.datetime.strptime(res_time, '%a %b %d %H:%M:%S %Y')
    print("UTC Time:", utc_time)
    # 2020-06-19 10:46:21
    
    #----------------------------------第三步 全球时区转换-------------------------------
    #http://zh.thetimenow.com/india
    #UTC时间比北京时间晚八个小时 故用timedelta方法加上八个小时
    china_time = datetime.datetime.strptime(res_time, '%a %b %d %H:%M:%S %Y') + datetime.timedelta(hours=8)
    print("China Time:",china_time)
    
    #美国 UTC-5
    america_time = datetime.datetime.strptime(res_time, '%a %b %d %H:%M:%S %Y') - datetime.timedelta(hours=5)
    print("America Time:",america_time)
    
    #印度 UTC+5
    india_time = datetime.datetime.strptime(res_time, '%a %b %d %H:%M:%S %Y') + datetime.timedelta(hours=5)
    print("India Time:",india_time)
    
    #澳大利亚 UTC+10
    australia_time = datetime.datetime.strptime(res_time, '%a %b %d %H:%M:%S %Y') + datetime.timedelta(hours=10)
    print("Australia Time",australia_time)
    
    #俄罗斯 UTC+3
    russia_time = datetime.datetime.strptime(res_time, '%a %b %d %H:%M:%S %Y') + datetime.timedelta(hours=3)
    print("Russia Time",russia_time)
    
    #英国 UTC+0
    england_time = datetime.datetime.strptime(res_time, '%a %b %d %H:%M:%S %Y')
    print("England Time",england_time)
    
    #日本 UTC+9
    japan_time = datetime.datetime.strptime(res_time, '%a %b %d %H:%M:%S %Y') + datetime.timedelta(hours=9)
    print("Japan Time",england_time)
    
    #德国 UTC+1
    germany_time = datetime.datetime.strptime(res_time, '%a %b %d %H:%M:%S %Y') + datetime.timedelta(hours=1)
    print("Germany Time",germany_time)
    
    #法国 UTC+1
    france_time = datetime.datetime.strptime(res_time, '%a %b %d %H:%M:%S %Y') + datetime.timedelta(hours=1)
    print("France Time",france_time)
    
    #加拿大 UTC-5
    canada_time = datetime.datetime.strptime(res_time, '%a %b %d %H:%M:%S %Y') - datetime.timedelta(hours=5)
    print("Canada Time:",canada_time)
    
    #越南 UTC+7 
    vietnam_time = datetime.datetime.strptime(res_time, '%a %b %d %H:%M:%S %Y') + datetime.timedelta(hours=7)
    print("Vietnam Time:",vietnam_time)
    

    输出结果如下图所示,不同地区有对应的时间分布,如果正常作息是早上9点到12点、下午2点到5点,从结果看更像是来自India、England、Japan等地区。当然,只有恶意样本很多、持续攻击的时候,单个样本意义并不大,我们才能进行更好的溯源,哈哈~

    在这里插入图片描述



    五.总结

    写到这里,这篇文章就介绍完毕,这三个技术在恶意代码溯源和分析中都非常普遍,希望对您有所帮助,最后进行简单的总结下。

    • PE文件
      PE文件基础
      PE文件格式解析
    • 编写代码提取IAT表
    • 二进制PE文件转字符串
    • 自动提取PE文件时间戳

    学安全一年,认识了很多安全大佬和朋友,希望大家一起进步。这篇文章中如果存在一些不足,还请海涵。作者作为网络安全初学者的慢慢成长路吧!希望未来能更透彻撰写相关文章。同时非常感谢参考文献中的安全大佬们的文章分享,深知自己很菜,得努力前行。

    有点想家和女神了!月是故乡圆啊~接着加油。

    编程没有捷径,逆向也没有捷径,它们都是搬砖活,少琢磨技巧,干就对了。什么时候你把攻击对手按在地上摩擦,你就赢了,也会慢慢形成了自己的安全经验和技巧。加油吧,少年希望这个路线对你有所帮助,共勉。

    (By:Eastmount 2020-08-12 星期三 中午2点写于武汉 http://blog.csdn.net/eastmount/ )



    2020年8月18新开的“娜璋AI安全之家”,主要围绕Python大数据分析、网络空间安全、人工智能、Web渗透及攻防技术进行讲解,同时分享CCF、SCI、南核北核论文的算法实现。娜璋之家会更加系统,并重构作者的所有文章,从零讲解Python和安全,写了近十年文章,真心想把自己所学所感所做分享出来,还请各位多多指教,真诚邀请您的关注!谢谢。

    展开全文
  • 应该说,这四项数据都重要、缺一不可的。缺少其中任何一项或任何一项中的数据不完整,物料需求计划的制订都将不准确的。因此,在制订物料需求计划之前,这四项数据都必须先完整地建立好,而且保证绝对可靠...
  • Socket网络通讯_TCP协议

    2020-10-04 16:24:32
    男生去女生宿舍找对象,进女生宿舍的第一就是宿管大妈,你告诉宿管大妈你要找哪个房间号(端口号)的女生 服务器至少需要两个Socket,一个负责监听、一个负责联系 两种协议:1️⃣TCP(次握手) 2️⃣...

    Socket网络通讯即如上图所示

    图中IP代表服务器地址,那么端口是什么呢?

    🌰男生去女生宿舍找对象,进女生宿舍的第一关就是宿管大妈,你告诉宿管大妈你要找哪哪个房间号(端口号)的哪女生

    服务器至少需要两个Socket,一个负责监听、一个负责联系

    两种协议:1️⃣TCP(三次握手) 2️⃣UDP(效率高但不稳定)

    我们常用TCP协议,因为TCP协议传输数据时数据不容易丢失(安全、稳定、但效率低)

    下面就举一个简单的🌰

    左侧为发送数据的输入框,单击“发送数据”把数据发送到指定IP地址的指定端口号。(本例中,IP地址和端口号都被写死到代码中)

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    using System.Net;
    using System.Net.Sockets;
    using System.IO;
    using System.Threading;
    
    namespace TcpClientTest
    {
        public partial class FormMain : Form
        {
            public FormMain()
            {
                InitializeComponent();
            }
    
            private void FormMain_Load(object sender, EventArgs e)
            {
                //初始化控件
                txtSendMssg.Text = "测试数据";
    
                //打开Listener开始监听
                Thread thrListener = new Thread(new ThreadStart(Listen));
                thrListener.Start();
            }
    
            private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
            {
                //强制关闭程序(强行终止Listener)
                Environment.Exit(0);
            }
    
            //发送数据
            private void btnSend_Click(object sender, EventArgs e)
            {
                TcpClient tcpClient = new TcpClient();
    
                //如果不想让IP被写死那就写IPAdress ip = IPAdress.Any;
    
                //tcpClient.Connect(IPAddress.Parse("170.0.0.78"), 2014);
                tcpClient.Connect(IPAddress.Parse("127.0.0.1"), 2014);
    
                NetworkStream ntwStream = tcpClient.GetStream();
                if (ntwStream.CanWrite)
                {
                    Byte[] bytSend = Encoding.UTF8.GetBytes(txtSendMssg.Text);
                    ntwStream.Write(bytSend, 0, bytSend.Length);
                }
                else
                {
                    MessageBox.Show("无法写入数据流");
    
                    ntwStream.Close();
                    tcpClient.Close();
    
                    return;
                }
    
                ntwStream.Close();
                tcpClient.Close();
            }
    
            //监听数据
            private void Listen()
            {
                Socket listener = new Socket(AddressFamily.InterNetwork, 
                    SocketType.Stream, ProtocolType.Tcp);
                listener.Bind(new IPEndPoint(IPAddress.Any, 2014));
    
                //不断监听端口
                while (true)
                {
                    listener.Listen(0);
                    Socket socket = listener.Accept();
                    NetworkStream ntwStream = new NetworkStream(socket);
                    StreamReader strmReader = new StreamReader(ntwStream);
                    Invoke(new PrintRecvMssgDelegate(PrintRecvMssg), 
                        new object[] { strmReader.ReadToEnd() });
                    socket.Close();
                }
    
                //程序的listener一直不关闭
                //listener.Close();
            }
    
            //线程内向文本框txtRecvMssg中添加字符串及委托
            private delegate void PrintRecvMssgDelegate(string s);
            private void PrintRecvMssg(string info)
            {
                txtRecvMssg.Text += string.Format("[{0}]:{1}\r\n", 
                    DateTime.Now.ToLongTimeString(), info);
            }
        }
    }

    在发送数据的文本框中分别输入“千山鸟飞绝”、“万径人踪灭”、“孤舟蓑笠翁”、“独钓寒江雪”四句话,输完一句话,单击一次“发送数据”按钮,就可以在接收数据里看到这四句话了。上面代码中,信息的发送时通过TcpClient连接到127.0.0.1的2014端口,信息的接收是通过Listen函数不断监听本机的2014端口实现的。从自己创建的线程中修改控件信息,用到了委托。

    Socket的Send方法,并非大家想象中的从一个端口发送消息到另一个端口,它仅仅是拷贝数据到基础系统的发送缓冲区,然后由基础系统将发送缓冲区的数据到连接的另一端口。值得一说的是,这里的拷贝数据与异步发送消息的拷贝是不一样的同步发送的拷贝,是直接拷贝数据到基础系统缓冲区,拷贝完成后返回,在拷贝的过程中,执行线程会IO等待, 此种拷贝与Socket自带的Buffer空间无关,但异步发送消息的拷贝,是将Socket自带的Buffer空间内的所有数据,拷贝到基础系统发送缓冲区,并立即返回,执行线程无需IO等待,所以异步发送在发送必须执行SetBuffer方法,拷贝完成后,会触发你自定义回调函数ProcessSend,在ProcessSend方法中,调用SetBuffer方法,重新初始化Buffer空间。

    展开全文
  • 我把他了起来,任凭他挥舞着八条腿也无能为力,他幼小的身体里流动着青色的血液,刚刚还在某个地方栖息的他突然来到这个没有安全感的地方,他一定愤怒至极,于是这个弱小的家伙开始尝试离开这个鬼地方,他慢慢地,...
  • 汽车驾驶教程图解

    2012-05-26 08:56:12
    安全带时,不要将摘下的安全带马上撒手,以防安全带金属扣弹回,打碎玻璃或伤到人。所以,必须手拿安全带将其慢慢送回。 总结 那么,现在让我们来复习一下。 1.锁好车门 不只是要锁好驾驶席车门,还应确认其他...
  • .如何得到Linux?.............................................................................................................3 四.如何得到Linux的最新消息?...........................................
  • 对于制造业来说,各种市场数据、客户数据、交易历史数据、社会综合数据都公司至重要的资产,企业运行的命脉。在企业数据电子化的基础上,保护企业的关键数据并加以合理利用已成为企业成功的关键因素。因此,对...
  • C#微软培训教材(高清PDF)

    千次下载 热门讨论 2009-07-30 08:51:17
    附录 A 键 字.255 附录 B 错 误 码.256 附录 C .Net 名字空间成员速查.269 参 考 资 料 .300 <<page 4>> page begin==================== 第一部分 C#语言概述 第一章 第一章第一章 第一章 ...
  • C#微软培训资料

    2014-01-22 14:10:17
    附录 A 键 字.255 附录 B 错 误 码.256 附录 C .Net 名字空间成员速查.269 参 考 资 料 .300 <<page 4>> page begin==================== 第一部分 C#语言概述 第一章 第一章第一章 第一章 ...
  • 变压器文本

    2013-07-21 11:42:44
    如果是变频器出现故障,如何去判断是哪一部分问题,在这里略作介绍。评论|赞同8 qq137782072 |六级采纳率51% 擅长:生活常识文化/艺术福建社会民生体育/运动 按默认排序|按时间排序 其他5条回答 2012-05-06 21:...
  • 16.6 决定采用种加密技术 670 16.7 小结 671 索引 672 译者序  Oracle Database 11g的推出让关注Oracle的人欣喜万分,不过也不免有些担心,因为此前还没有合适的书系统而深入地介绍这个新版本。要想学习和...
  • php高级开发教程说明

    2008-11-27 11:39:22
    当从事一个专业项目的时候,考虑一下你正在做什么重要的,“了解你的敌人,永远 不要低估它”。尽管你的项目并不是一个真正的敌人,这句话的寓意仍然适用,在转向其他题目 时,要知道项目的所有技术条件、目标...
  • 个基本状态等待、执行和就绪,在一定的条件下,进程的状态将发生转换。 (2)进程调度算法 主要有先来先服务(FCFS)、时间片轮转法、多级反馈轮转法、优先数法。 (3)进程控制块(PCB)进程...
  • C++网络爬虫项目

    2018-07-04 00:59:17
    一个网页重要性,即 些网页质量较好或相对重要的,而这往往可以从“链接分析”的结果中获 得。综合以上两种考虑,前台系统对网页进行排序,作为搜索的最终结果。 除了上述功能模块,搜索引擎的“反作弊”模块...
  • 计算机实习日记

    2011-11-26 12:22:41
    新来的员工,比较不忙,能说不行啊,就接过来了。接过来我一看,好家伙,密密麻麻少说也有四千字啊,没办法,赶紧开始打吧。好在我在学校也经常打字练习,盲打每分钟也能打六七十个汉字,经过一个多小时的...
  • 对于一个DBA来讲,当你拿到一个数据库的时候,你首先需要做的用最短的时间来了解一下跑在这个库上的一个什么系统,比如在线事务(OLTP)系统还是在线分析(OLAP)系统,这对于你做出性能上的判断至重要,...
  • 软件工程教程

    热门讨论 2012-07-06 23:10:29
    监听删除操作,保证数据的安全。 场景 监听删除操作 删除操作一旦执行,立即被监听器捕获到,进而在执行 删除操作前执行自定义的函数体,即判断实体有无undeletable标签,有则中断删除操作,无则正常删除。 用例图...
  •  本书一本关于Oracle 9i & 10g数据库体系结构的权威图书,涵盖了所有最重要的Oracle体系结构特性,包括文件、内存结构和进程,锁和闩,事务、并发和多版本,表和索引,数据类型,以及分区和并行,并利用具体的...
  • 如果设置为 SIGNATURE, 在签名安全的情况下即可执行该过程。 值范围: TIMESTAMP | SIGNATURE 默认值: TIMESTAMP utl_file_dir: 说明: 允许数据库管理员指定 PL/SQL 文件 I/O 许可的目录。使用多个 UTL_FILE_DIR ...

空空如也

空空如也

1 2
收藏数 23
精华内容 9
关键字:

安全三关是哪三关