LyScript 实现Hook隐藏调试器
LyScript 插件集成的内置API函数可灵活的实现绕过各类反调试保护机制,前段时间发布的那一篇文章并没有详细讲解各类反调试机制的绕过措施,本次将补充这方面的知识点,运用LyScript实现绕过大多数通用调试机制,实现隐藏调试器的目的。
我们以此实现Patches如下函数:
- IsDebuggerPresent
- ZwQueryInformationProcess
- CheckRemoteDebuggerPresent
- PEB.IsDebugged
- PEB.ProcessHeap.Flag
- PEB.NtGlobalFlag
- PEB.Ldr 0xFEEEFEEE filling
- GetTickCount
- ZwQuerySystemInformation
- FindWindowA
- FindWindowW
- FindWindowExA
- FindWindowExW
- EnumWindows
首先第一步我们需要自己封装实现一个反汇编转机器码的函数,其作用是当用户传入汇编列表时,自动将其转为机器码并输出为列表格式。
from LyScript32 import MyDebug
# 传入汇编代码,得到对应机器码
def get_opcode_from_assemble(dbg_ptr,asm):
byte_code = bytearray()
addr = dbg_ptr.create_alloc(1024)
if addr != 0:
asm_size = dbg_ptr.assemble_code_size(asm)
# print("汇编代码占用字节: {}".format(asm_size))
write = dbg_ptr.assemble_write_memory(addr,asm)
if write == True:
for index in range(0,asm_size):
read = dbg_ptr.read_memory_byte(addr + index)
# print("{:02x} ".format(read),end="")
byte_code.append(read)
dbg_ptr.delete_alloc(addr)
return byte_code
else:
return bytearray(0)
# 传入汇编机器码得到机器码列表
def GetOpCode(dbg, Code):
ShellCode = []
for index in Code:
ref = get_opcode_from_assemble(dbg,index)
for opcode in ref:
ShellCode.append(opcode)
return ShellCode
if __name__ == "__main__":
dbg = MyDebug()
connect = dbg.connect()
ShellCode = GetOpCode(dbg, ["DB 0x64","mov eax,dword ptr ds:[18]","sub eax,eax","ret"])
print(ShellCode)
dbg.close()
输出效果如下:

Patch_PEB
PEB结构存在许多反调试变量,首先我们需要先将这些变量填充为空。
# ----------------------------------------------
# By: LyShark
# Email: me@lyshark.com
# Project: https://github.com/lyshark/LyScript
# ----------------------------------------------
from LyScript32 import MyDebug
# 传入汇编代码,得到对应机器码
def get_opcode_from_assemble(dbg_ptr,asm):
byte_code = bytearray()
addr = dbg_ptr.create_alloc(1024)
if addr != 0:
asm_size = dbg_ptr.assemble_code_size(asm)
# print("汇编代码占用字节: {}".format(asm_size))
write = dbg_ptr.assemble_write_memory(addr,asm)
if write == True:
for index in range(0,asm_size):
read = dbg_ptr.read_memory_byte(addr + index)
# print("{:02x} ".format(read),end="")
byte_code.append(read)
dbg_ptr.delete_alloc(addr)
return byte_code
else:
return bytearray(0)
# 传入汇编机器码得到机器码列表
def GetOpCode(dbg, Code):
ShellCode = []
for index in Code:
ref = get_opcode_from_assemble(dbg,index)
for opcode in ref:
ShellCode.append(opcode)
return ShellCode
def Patch_PEB(dbg):
PEB = dbg.get_peb_address(dbg.get_process_id())
if PEB == 0:
return 0
# 写出0 Patching PEB.IsDebugged
dbg.write_memory_byte(PEB + 0x2,GetOpCode(dbg,["db 0"])[0])
print("补丁地址: {}".format(hex(PEB+0x2)))
# 写出0 Patching PEB.ProcessHeap.Flag
temp = dbg.read_memory_dword(PEB + 0x18)
temp += 0x10
dbg.write_memory_dword(temp, GetOpCode(dbg,["db 0"])[0])
print(("补丁地址: {}".format(hex(temp))))
# 写出0 atching PEB.NtGlobalFlag
dbg.write_memory_dword(PEB+0x68, 0)
print(("补丁地址: {}".format(hex(PEB+0x68))))
# 循环替换 Patch PEB_LDR_DATA 0xFEEEFEEE fill bytes about 3000 of them
addr = dbg.read_memory_dword(PEB + 0x0c)
while addr != 0:
addr += 1
try:
b = dbg.read_memory_dword(addr)
c = dbg.read_memory_dword(addr + 4)
# 仅修补填充运行
print(b)
if (b == 0xFEEEFEEE) and (c == 0xFEEEFEEE):
dbg.write_memory_dword(addr,0)
dbg.write_memory_dword(addr + 4, 0)
print("patch")
except Exception:
break
if __name__ == "__main__":
dbg = MyDebug()
connect = dbg.connect()
Patch_PEB(dbg)
dbg.close()
Patch_IsDebuggerPresent
该函数用于检测自身是否处于调试状态,其C系列代码如下所示,绕过此种方式很简单,只需要在函数头部写出ret指令即可。
#include <Windows.h>
#include <stdio.h>
int _tmain(int argc, _TCHAR* argv[])
{
BOOL ref = IsDebuggerPresent();
printf("是否被调试: %d \n", ref);
getchar();
return 0;
}
注意:此Api检查PEB中的值,因此如果修补PEB,则无需修补Api,这段绕过代码如下。
from LyScript32 import MyDebug
# 传入汇编代码,得到对应机器码
def get_opcode_from_assemble(dbg_ptr,asm):
byte_code = bytearray()
addr = dbg_ptr.create_alloc(1024)
if addr != 0:
asm_size = dbg_ptr.assemble_code_size(asm)
# print("汇编代码占用字节: {}".format(asm_size))
write = dbg_ptr.assemble_write_memory(addr,asm)
if write == True:
for index in range(0,asm_size):
read = dbg_ptr.read_memory_byte(addr + index)
# print("{:02x} ".format(read),end="")
byte_code.append(read)
dbg_ptr.delete_alloc(addr)
return byte_code
else:
return bytearray(0)
# 传入汇编机器码得到机器码列表
def GetOpCode(dbg, Code):
ShellCode = []
for index in Code:
ref = get_opcode_from_assemble(dbg,index)
for opcode in ref:
ShellCode.append(opcode)
return ShellCode
def Patch_IsDebuggerPresent(dbg):
# 得到模块句柄
ispresent = dbg.get_module_from_function("kernel32.dll","IsDebuggerPresent")
print(hex(ispresent))
if(ispresent <= 0):
print("无法得到模块基地址,请以管理员方式运行调试器.")
return 0
# 将反调试语句转为机器码
ShellCode = GetOpCode(dbg, ["DB 0x64", "mov eax,dword ptr ds:[18]", "sub eax,eax", "ret"])
print(ShellCode)
flag = 0
for index in range(0,len(ShellCode)):
flag = dbg.write_memory_byte(ispresent + index,ShellCode[index])
if flag:
flag = 1
else:
flag = 0
return flag
if __name__ == "__main__":
dbg = MyDebug()
connect = dbg.connect()
ref = Patch_IsDebuggerPresent(dbg)
print("补丁状态: {}".format(ref))
dbg.close()
当程序运行后会向IsDebuggerPresent函数写出返回,从而实现绕过调试的目的。

Patch_CheckRemoteDebuggerPresent
此Api调用ZwQueryInformationProcess因此通常不需要对两者进行修补。
from LyScript32 import MyDebug
# 传入汇编代码,得到对应机器码
def get_opcode_from_assemble(dbg_ptr,asm):
byte_code = bytearray()
addr = dbg_ptr.create_alloc(1024)
if addr != 0:
asm_size = dbg_ptr.assemble_code_size(asm)
# print("汇编代码占用字节: {}".format(asm_size))
write = dbg_ptr.assemble_write_memory(addr,asm)
if write == True:
for index in range(0,asm_size):
read = dbg_ptr.read_memory_byte(addr + index)
# print("{:02x} ".format(read),end="")
byte_code.append(read)
dbg_ptr.delete_alloc(addr)
return byte_code
else:
return bytearray(0)
# 传入汇编机器码得到机器码列表
def GetOpCode(dbg, Code):
ShellCode = []
for index in Code:
ref = get_opcode_from_assemble(dbg,index)
for opcode in ref:
ShellCode.append(opcode)
return ShellCode
def Patch_CheckRemoteDebuggerPresent(dbg):
# 得到模块句柄
ispresent = dbg.get_module_from_function("kernel32.dll","CheckRemoteDebuggerPresent")
print(hex(ispresent))
# 将反调试语句转为机器码
ShellCode = GetOpCode(dbg,
[
"mov edi,edi",
"push ebp",
"mov ebp,esp",
"mov eax,[ebp+0xc]",
"push 0",
"pop dword ptr ds:[eax]",
"xor eax,eax",
"pop ebp",
"ret 8"
]
)
print(ShellCode)
flag = 0
for index in range(0,len(ShellCode)):
flag = dbg.write_memory_byte(ispresent + index,ShellCode[index])
if flag:
flag = 1
else:
flag = 0
return flag
if __name__ == "__main__":
dbg = MyDebug()
connect = dbg.connect()
ref = Patch_CheckRemoteDebuggerPresent(dbg)
print("写出状态: {}".format(ref))
dbg.close()
写出效果如下:

Patch_GetTickCount
GetTickCount返回(retrieve)从操作系统启动所经过(elapsed)的毫秒数,常用于定时计数,绕过方式只需初始化即可。
from LyScript32 import MyDebug
# 传入汇编代码,得到对应机器码
def get_opcode_from_assemble(dbg_ptr,asm):
byte_code = bytearray()
addr = dbg_ptr.create_alloc(1024)
if addr != 0:
asm_size = dbg_ptr.assemble_code_size(asm)
# print("汇编代码占用字节: {}".format(asm_size))
write = dbg_ptr.assemble_write_memory(addr,asm)
if write == True:
for index in range(0,asm_size):
read = dbg_ptr.read_memory_byte(addr + index)
# print("{:02x} ".format(read),end="")
byte_code.append(read)
dbg_ptr.delete_alloc(addr)
return byte_code
else:
return bytearray(0)
# 传入汇编机器码得到机器码列表
def GetOpCode(dbg, Code):
ShellCode = []
for index in Code:
ref = get_opcode_from_assemble(dbg,index)
for opcode in ref:
ShellCode.append(opcode)
return ShellCode
def Patch_GetTickCount(dbg):
# 得到模块句柄
ispresent = dbg.get_module_from_function("kernel32.dll","GetTickCount")
print(hex(ispresent))
# 将反调试语句转为机器码
ShellCode = GetOpCode(dbg,
[
"mov edx,0x7ffe0000",
"sub eax,eax",
"add eax,0xB0B1560D",
"ret"
]
)
print(ShellCode)
flag = 0
for index in range(0,len(ShellCode)):
flag = dbg.write_memory_byte(ispresent + index,ShellCode[index])
if flag:
flag = 1
else:
flag = 0
return flag
if __name__ == "__main__":
dbg = MyDebug()
connect = dbg.connect()
ref = Patch_GetTickCount(dbg)
print("写出状态: {}".format(ref))
dbg.close()
写出效果如下:

Patch_ZwQueryInformationProcess
此函数打补丁需要跳转两次,原因是因为函数开头部分无法填充更多指令,需要我们自己来申请空间,并实现跳转。
# ----------------------------------------------
# By: LyShark
# Email: me@lyshark.com
# Project: https://github.com/lyshark/LyScript
# ----------------------------------------------
from LyScript32 import MyDebug
# 传入汇编代码,得到对应机器码
def get_opcode_from_assemble(dbg_ptr,asm):
byte_code = bytearray()
addr = dbg_ptr.create_alloc(1024)
if addr != 0:
asm_size = dbg_ptr.assemble_code_size(asm)
# print("汇编代码占用字节: {}".format(asm_size))
write = dbg_ptr.assemble_write_memory(addr,asm)
if write == True:
for index in range(0,asm_size):
read = dbg_ptr.read_memory_byte(addr + index)
# print("{:02x} ".format(read),end="")
byte_code.append(read)
dbg_ptr.delete_alloc(addr)
return byte_code
else:
return bytearray(0)
# 传入汇编机器码得到机器码列表
def GetOpCode(dbg, Code):
ShellCode = []
for index in Code:
ref = get_opcode_from_assemble(dbg,index)
for opcode in ref:
ShellCode.append(opcode)
return ShellCode
# 获取指定位置前index条指令的长度
def GetOpCodeSize(dbg,address,index):
ref_size = 0
dasm = dbg.get_disasm_code(address,index)
for index in dasm:
count = dbg.assemble_code_size(index.get("opcode"))
ref_size += count
return ref_size
def Patch_ZwQueryInformationProcess(dbg):
# 得到模块句柄
ispresent = dbg.get_module_from_function("ntdll.dll","ZwQueryInformationProcess")
print(hex(ispresent))
create_address = dbg.create_alloc(1024)
print("分配空间: {}".format(hex(create_address)))
# 将反调试语句转为机器码
ShellCode = GetOpCode(dbg,
[
"cmp dword [esp + 8],7",
"DB 0x74",
"DB 0x06",
f"push {hex(ispresent)}",
"ret",
"mov eax,dword [esp +0x0c]",
"push 0",
"pop dword [eax]",
"xor eax,eax",
"ret 14"
]
)
print(ShellCode)
# 把shellcode写出到自己分配的堆中
flag = 0
for index in range(0,len(ShellCode)):
flag = dbg.write_memory_byte(create_address + index,ShellCode[index])
if flag:
flag = 1
else:
flag = 0
# 填充跳转位置
jmp_shellcode = GetOpCode(dbg,
[
f"push {hex(create_address)}",
"ret"
]
)
for index in range(0,len(jmp_shellcode)):
flag = dbg.write_memory_byte(ispresent + index,jmp_shellcode[index])
if flag:
flag = 1
else:
flag = 0
return flag
if __name__ == "__main__":
dbg = MyDebug()
connect = dbg.connect()
ref = Patch_ZwQueryInformationProcess(dbg)
print("补丁状态: {}".format(ref))
dbg.close()
这段代码运行后,首先会申请内存,然后将特定的一段机器码写出到此内存中。

内存写出以后,再将函数头部替换为跳转,这样一来当函数被调用,也就自动转向了。

Patch_FindWindow
FindWindow函数功能是取窗体句柄,有AW与Ex系列,使用同上方法替代即可。
# ----------------------------------------------
# By: LyShark
# Email: me@lyshark.com
# Project: https://github.com/lyshark/LyScript
# ----------------------------------------------
from LyScript32 import MyDebug
import ctypes
# 传入汇编代码,得到对应机器码
def get_opcode_from_assemble(dbg_ptr,asm):
byte_code = bytearray()
addr = dbg_ptr.create_alloc(1024)
if addr != 0:
asm_size = dbg_ptr.assemble_code_size(asm)
# print("汇编代码占用字节: {}".format(asm_size))
write = dbg_ptr.assemble_write_memory(addr,asm)
if write == True:
for index in range(0,asm_size):
read = dbg_ptr.read_memory_byte(addr + index)
# print("{:02x} ".format(read),end="")
byte_code.append(read)
dbg_ptr.delete_alloc(addr)
return byte_code
else:
return bytearray(0)
# 传入汇编机器码得到机器码列表
def GetOpCode(dbg, Code):
ShellCode = []
for index in Code:
ref = get_opcode_from_assemble(dbg,index)
for opcode in ref:
ShellCode.append(opcode)
return ShellCode
def Patch_FindWindow(dbg):
# 得到模块句柄
FindWindowA = dbg.get_module_from_function("user32.dll","FindWindowA")
FindWindowW = dbg.get_module_from_function("user32.dll","FindWindowW")
FindWindowExA = dbg.get_module_from_function("user32.dll","FindWindowExA")
FindWindowExW = dbg.get_module_from_function("user32.dll","FindWindowExW")
print("A = {} w = {} exA = {} exW = {}".format(hex(FindWindowA),hex(FindWindowW),hex(FindWindowExA),hex(FindWindowExW)))
# 将反调试语句转为机器码
ShellCode = GetOpCode(dbg,
[
"xor eax,eax",
"ret 0x8",
]
)
ShellCodeEx = GetOpCode(dbg,
[
"xor eax,eax",
"ret 0x10",
]
)
# 写出
flag = 0
for index in range(0,len(ShellCode)):
flag = dbg.write_memory_byte(FindWindowA + index,ShellCode[index])
flag = dbg.write_memory_byte(FindWindowW + index,ShellCode[index])
if flag:
flag = 1
else:
flag = 0
for index in range(0,len(ShellCodeEx)):
flag = dbg.write_memory_byte(FindWindowExA + index,ShellCodeEx[index])
flag = dbg.write_memory_byte(FindWindowExW + index,ShellCodeEx[index])
if flag:
flag = 1
else:
flag = 0
return flag
if __name__ == "__main__":
dbg = MyDebug()
connect = dbg.connect()
ref = Patch_FindWindow(dbg)
print("补丁状态: {}".format(ref))
dbg.close()
补丁应用会分别替换四个函数。

Patch_EnumWindows
枚举窗体的补丁与上方代码一致,此处就不再分析了。
如下案例,实现了在枚举窗体过程中实现弹窗,并不影响窗体的枚举。
from LyScript32 import MyDebug
# 传入汇编代码,得到对应机器码
def get_opcode_from_assemble(dbg_ptr,asm):
byte_code = bytearray()
addr = dbg_ptr.create_alloc(1024)
if addr != 0:
asm_size = dbg_ptr.assemble_code_size(asm)
# print("汇编代码占用字节: {}".format(asm_size))
write = dbg_ptr.assemble_write_memory(addr,asm)
if write == True:
for index in range(0,asm_size):
read = dbg_ptr.read_memory_byte(addr + index)
# print("{:02x} ".format(read),end="")
byte_code.append(read)
dbg_ptr.delete_alloc(addr)
return byte_code
else:
return bytearray(0)
# 传入汇编机器码得到机器码列表
def GetOpCode(dbg, Code):
ShellCode = []
for index in Code:
ref = get_opcode_from_assemble(dbg,index)
for opcode in ref:
ShellCode.append(opcode)
return ShellCode
# 获取指定位置前index条指令的长度
def GetOpCodeSize(dbg,address,index):
ref_size = 0
dasm = dbg.get_disasm_code(address,index)
for index in dasm:
count = dbg.assemble_code_size(index.get("opcode"))
ref_size += count
return ref_size
def Patch_EnumWindows(dbg):
# 得到模块句柄
address = dbg.get_module_from_function("user32.dll","EnumWindows")
print(hex(address))
msg_box = dbg.get_module_from_function("user32.dll","MessageBoxA")
print(hex(msg_box))
create_address = dbg.create_alloc(1024)
print("分配空间: {}".format(hex(create_address)))
# 找call地址,找到后取出他的内存地址
dasm_list = dbg.get_disasm_code(address,20)
call_addr = 0
call_next_addr = 0
for index in range(0,len(dasm_list)):
# 如果找到了call,取出call地址以及下一条地址
if dasm_list[index].get("opcode").split(" ")[0] == "call":
call_addr = dasm_list[index].get("addr")
call_next_addr = dasm_list[index+1].get("addr")
print("call = {} call_next = {}".format(hex(call_addr),hex(call_next_addr)))
# 将反调试语句转为机器码
ShellCode = GetOpCode(dbg,
[
"push 0",
"push 0",
"push 0",
"push 0",
f"call {hex(msg_box)}",
"mov eax,1",
"pop ebp",
"ret 10",
f"call {hex(call_addr)}",
"pop ebp",
"ret 8"
]
)
print(ShellCode)
# 把shellcode写出到自己分配的堆中
flag = 0
for index in range(0,len(ShellCode)):
flag = dbg.write_memory_byte(create_address + index,ShellCode[index])
if flag:
flag = 1
else:
flag = 0
# 填充跳转位置
jmp_shellcode = GetOpCode(dbg,
[
f"push {hex(create_address)}",
"ret"
]
)
for index in range(0,len(jmp_shellcode)):
flag = dbg.write_memory_byte(call_addr + index,jmp_shellcode[index])
if flag:
flag = 1
else:
flag = 0
return flag
if __name__ == "__main__":
dbg = MyDebug()
connect = dbg.connect()
ref = Patch_EnumWindows(dbg)
dbg.close()
输出效果如下:

LyScript 实现Hook隐藏调试器的更多相关文章
- iOS - 浅谈LLDB调试器
摘要 LLDB是Xcode默认的调试器,它与LLVM编译器一起,带给我们更丰富的流程控制和数据检测的调试功能.平时用Xcode运行程序,实际走的都是LLDB.熟练使用LLDB,可以让你debug事半功 ...
- Linux C编程学习之开发工具2---GDB调试器
简介 GDB是一个功能强大的交互式程序调试工具,主要工作在字符界面下. GDB不仅可以用来调试C/C++ 语言编写的程序,还可以用来调试 Pascal.Objective-C,以及Fortran等语言 ...
- C#调试器导航
本快速入门演示如何在 Visual Studio 调试会话中导航,以及如何在会话中查看和更改程序状态. 本 快速入门适用于不熟悉用 Visual Studio 进行调试的开发人员,以及要详细了解在 V ...
- iOS LLDB调试器和断点调试
技巧一:运行时修改变量的值 你以前怎么验证是不是某个变量的值导致整段程序不能正常工作?修改代码中的变量的值,然后cmd+r重新启动app?现在你不需要这么做了,只需要设置一个断点,当程序在这进入调试模 ...
- 第二章排错的工具:调试器Windbg(下)
感谢博主 http://book.51cto.com/art/200711/59874.htm 2.2 读懂机器的语言:汇编,CPU执行指令的最小单元2.2.1 需要用汇编来排错的常见情况 汇编是 ...
- 32位汇编第一讲x86和8086的区别,以及OllyDbg调试器的使用
32位汇编第一讲x86和8086的区别,以及OllyDbg调试器的使用 一丶32位(x86也称为80386)与8086(16位)汇编的区别 1.寄存器的改变 AX 变为 EAX 可以这样想,16位通 ...
- 学习笔记之--认识Xcode中的重要成员:lldb调试器
之前对lldb调试器了解比较少,平时主要用来打印日志和暂定时用鼠标查看属性数据以及使用p po一些简单的命令语句. 今天看了一些关于lldb的文章,顿时觉得之前对它了解太少了,原来它还有那么多的功能. ...
- .NET dnSpy 程序集编辑器,反编译器和调试器
https://github.com/0xd4d/dnSpy https://github.com/0xd4d/dnSpy/releases/ dnSpy是反向工程.NET程序集的工具.它包括一个反编 ...
- 使用 JDB 调试器
您可以使用调试 applet 或应用程序的 jdb 命令来调试 Servlet. 为了调试一个 Servlet,我们可以调试 sun.servlet.http.HttpServer,然后把它看成是 H ...
- 手把手教你写Windows 64位平台调试器
本文网页排版有些差,已上传了doc,可以下载阅读.本文中的所有代码已打包,下载地址在此. ------------------------------------------------------- ...
随机推荐
- leaflet 绘制 点 线 面 圆 椭圆 线缓冲区
leaflet有个绘图插件Leaflet.draw,但是我不想要它的控件,只想用它的绘制功能,控件我自己提供,当时不知道如何使用,就自己写了个绘制点线面圆和椭圆的工具,代码如下: /// <re ...
- 蓝桥杯历年省赛试题汇总 C/C++ A组
A组 省赛 B 组的题目可以在这里查看 → 刷题笔记: 蓝桥杯 题目提交网站:Here 2013 第四届 高斯日记 排它平方数 振兴中华 颠倒的价牌 前缀判断 逆波兰表达式 错误票据 买不到的数目 剪 ...
- 揭秘 vivo 如何打造千万级 DAU 活动中台 - 启航篇
本文首发于 vivo互联网技术 微信公众号 链接: https://mp.weixin.qq.com/s/Ka1pjJKuFwuVL8B-t7CwuA作者:悟空中台研发团队 vivo大厦(南京) 一 ...
- Java文件上传与下载压缩
文件上传与下载压缩 文件上传: 这是一个通用的本地文件的上传代码,可以将文件类型存储到相应的本地目录下 注:本次演示为存储路径为项目所在的resources目录下,可通过url去访问本地文件数据适用于 ...
- 四、java对mongo数据库增删改查操作
系列导航 一.linux单机版mongo安装(带密码验证) 二.mongo集群搭建 三.java连接mongo数据库 四.java对mongo数据库增删改查操作 五.mongo备份篇 mongoexp ...
- 机器学习-决策树系列-Adaboost算法-集成学习-29
目录 1. adaboost算法的基本思想 2. 具体实现 1. adaboost算法的基本思想 集成学习是将多个弱模型集成在一起 变成一个强模型 提高模型的准确率,一般有如下两种: bagging: ...
- Java标签在循环中的使用
定义 标签,类似--label1: 放在循环外部,用于内部多重循环语句的跳出 例子 public static void main(String[] args) { Scanner sc = new ...
- DC逻辑综合工具简介-Design Compiler
逻辑综合简介 逻辑综合:代码转变为网表 FPGA:代码转变为FPGA内部的数字单元 在进行综合的时候往往会使用一些脚本工具 需要学会看综合之后的报告 1.目标 进行综合需要读入RTL设计,还需要用到f ...
- Oracle数据库同时建立和使用两个监听器
1.问题 我分别对两个数据库实例(Lib和Orcl)各自建立了一个监听器,端口号分别为1520和1521,但是默认只启动一个,导致我切换数据库实例的时候, 出现以下问题:状态: 失败 -测试失败: I ...
- shell-命令行位置参数-$n