- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我试图在 32 位测试 linux 系统(Lubuntu)上用 python3 编写一个简单的调试器,它应该能够捕获任意程序的所有系统调用(在这种情况下:/bin/ls).为此,我使用 ptrace 系统调用来单步执行整个过程。在每一步之后,我读取寄存器以找到指令指针 eip 以从下一条指令读取 2 个字节。如果这 2 个字节是 0xcd 和 0x80,则表示 int 80 是系统调用。我知道还有用于此目的的 PTRACE_SYSCALL,但我想在不使用它的情况下执行此操作。
在下面我向您展示了代码,它似乎可以工作,但是有一些奇怪的行为:
为了弄清楚这是否有效,我使用 strace 将它的输出与我自己的系统调用进行比较。而且我的程序似乎只显示了系统调用的第一部分,第二部分就不见了。为了向您展示我在下面发布了我的程序和 strace 的输出。有人知道这里可能出了什么问题吗?
import os # os interaction
from struct import pack # dealing with bytes (ptrace)
import ctypes # support c data structures
""" ========================================================== """
# 32 bit reg process structrue
class UserRegsStruct(ctypes.Structure):
_fields_ = [
("ebx", ctypes.c_ulong),
("ecx", ctypes.c_ulong),
("edx", ctypes.c_ulong),
("esi", ctypes.c_ulong),
("edi", ctypes.c_ulong),
("ebp", ctypes.c_ulong),
("eax", ctypes.c_ulong),
("xds", ctypes.c_ulong),
("xes", ctypes.c_ulong),
("xfs", ctypes.c_ulong),
("xgs", ctypes.c_ulong),
("orig_eax", ctypes.c_ulong),
("eip", ctypes.c_ulong),
("xcs", ctypes.c_ulong),
("eflags", ctypes.c_ulong),
("esp", ctypes.c_ulong),
("xss", ctypes.c_ulong),
]
# ptrace constants
PTRACE_TRACEME = 0
PTRACE_PEEKDATA = 2
PTRACE_SINGLESTEP = 9
PTRACE_GETREGS = 12
CPU_WORD_SIZE = 4 # size of cpu word size (32 bit = 4 bytes)
# for syscalls
libc = ctypes.CDLL('libc.so.6')
# check if child (tracee) is still running
def WIFSTOPPED(status):
return (status & 0xff) == 0x7f
# read from process memory by PTRACE_PEEKDATA
def ReadProcessMemory(pid, address, size):
# address must be aligned!!
offset = address % CPU_WORD_SIZE
if offset:
address -= offset
word = libc.ptrace(PTRACE_PEEKDATA, pid, address, 0)
wordbytes = pack("i", word)
subsize = min(CPU_WORD_SIZE - offset, size)
data = wordbytes[offset:offset + subsize]
size -= subsize
address += CPU_WORD_SIZE
else:
data = bytes(0)
while size:
word = libc.ptrace(PTRACE_PEEKDATA, pid, address, 0)
wordbytes = pack("i", word)
if size < CPU_WORD_SIZE:
data += wordbytes[:size]
break
data += wordbytes
size -= CPU_WORD_SIZE
address += CPU_WORD_SIZE
return data
""" ========================================================== """
# extract syscall names
fp = open("/usr/include/i386-linux-gnu/asm/unistd_32.h", "r")
syscalls = [0] * 400
for line in fp:
if "__NR_" in line:
a = line.rstrip().split(" ")
name = a[1].split("NR_")[1]
number = int(a[2])
syscalls[number] = name
# "int 80" asm instruction = (0xCD 0x80)
a0 = 0xcd
a1 = 0x80
# create child tracee
pid = os.fork()
if pid == 0: # in tracee
libc.ptrace(PTRACE_TRACEME, 0, 0, 0) # make child traceable
os.execv("/bin/ls", [":-P"]) # run test programm
else: # in tracer
pid, status = os.waitpid(pid, 0)
regs = UserRegsStruct()
# catch all syscalls
while True:
libc.ptrace(PTRACE_SINGLESTEP, pid, 0, 0) # execute next instruction
pid, status = os.waitpid(pid, 0) # wait for tracee
libc.ptrace(PTRACE_GETREGS, pid, 0, ctypes.byref(regs)) # get register values
data = ReadProcessMemory(pid, regs.eip, 2) # read 2 bytes from instruction pointer address
# now check if this is a syscall
if data[0] == a0 and data[1] == a1:
print("HEUREKA! SYSCALL at " + hex(regs.eip) + ": " + syscalls[regs.eax])
if WIFSTOPPED(status) == False: break # exit loop when tracee stopped
这产生了以下输出:
HEUREKA! SYSCALL at 0xb7fae2c5: brk
HEUREKA! SYSCALL at 0xb7fa3944: access
HEUREKA! SYSCALL at 0xb7faf7ae: mmap2
HEUREKA! SYSCALL at 0xb7faf689: access
HEUREKA! SYSCALL at 0xb7faf4b5: openat
HEUREKA! SYSCALL at 0xb7faf419: fstat64
HEUREKA! SYSCALL at 0xb7faf7ae: mmap2
HEUREKA! SYSCALL at 0xb7faf755: close
HEUREKA! SYSCALL at 0xb7faa758: access
HEUREKA! SYSCALL at 0xb7faf4b5: openat
HEUREKA! SYSCALL at 0xb7faf57e: read
HEUREKA! SYSCALL at 0xb7faf419: fstat64
HEUREKA! SYSCALL at 0xb7faf7ae: mmap2
HEUREKA! SYSCALL at 0xb7faf7ae: mmap2
HEUREKA! SYSCALL at 0xb7faf7ae: mmap2
HEUREKA! SYSCALL at 0xb7faf755: close
HEUREKA! SYSCALL at 0xb7faa758: access
HEUREKA! SYSCALL at 0xb7faf4b5: openat
HEUREKA! SYSCALL at 0xb7faf57e: read
HEUREKA! SYSCALL at 0xb7faf419: fstat64
HEUREKA! SYSCALL at 0xb7faf7ae: mmap2
HEUREKA! SYSCALL at 0xb7faf822: mprotect
HEUREKA! SYSCALL at 0xb7faf7ae: mmap2
HEUREKA! SYSCALL at 0xb7faf7ae: mmap2
HEUREKA! SYSCALL at 0xb7faf755: close
HEUREKA! SYSCALL at 0xb7faa758: access
HEUREKA! SYSCALL at 0xb7faf4b5: openat
HEUREKA! SYSCALL at 0xb7faf57e: read
HEUREKA! SYSCALL at 0xb7faf419: fstat64
HEUREKA! SYSCALL at 0xb7faf7ae: mmap2
HEUREKA! SYSCALL at 0xb7faf7ae: mmap2
HEUREKA! SYSCALL at 0xb7faf755: close
HEUREKA! SYSCALL at 0xb7faa758: access
HEUREKA! SYSCALL at 0xb7faf4b5: openat
HEUREKA! SYSCALL at 0xb7faf57e: read
HEUREKA! SYSCALL at 0xb7faf419: fstat64
HEUREKA! SYSCALL at 0xb7faf7ae: mmap2
HEUREKA! SYSCALL at 0xb7faf7ae: mmap2
HEUREKA! SYSCALL at 0xb7faf755: close
HEUREKA! SYSCALL at 0xb7faa758: access
HEUREKA! SYSCALL at 0xb7faf4b5: openat
HEUREKA! SYSCALL at 0xb7faf57e: read
HEUREKA! SYSCALL at 0xb7faf419: fstat64
HEUREKA! SYSCALL at 0xb7faf7ae: mmap2
HEUREKA! SYSCALL at 0xb7faf7ae: mmap2
HEUREKA! SYSCALL at 0xb7faf7ae: mmap2
HEUREKA! SYSCALL at 0xb7faf755: close
HEUREKA! SYSCALL at 0xb7faf7ae: mmap2
HEUREKA! SYSCALL at 0xb7f95bd9: set_thread_area
HEUREKA! SYSCALL at 0xb7faf822: mprotect
HEUREKA! SYSCALL at 0xb7faf822: mprotect
HEUREKA! SYSCALL at 0xb7faf822: mprotect
HEUREKA! SYSCALL at 0xb7faf822: mprotect
HEUREKA! SYSCALL at 0xb7faf822: mprotect
HEUREKA! SYSCALL at 0xb7faf822: mprotect
HEUREKA! SYSCALL at 0xb7faf822: mprotect
HEUREKA! SYSCALL at 0xb7faf7ff: munmap
test.py
这是 strace 的输出:
execve("/bin/ls", ["/bin/ls"], 0xbfef5e40 /* 45 vars */) = 0
brk(NULL) = 0x220c000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f00000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=89915, ...}) = 0
mmap2(NULL, 89915, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7eea000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/i386-linux-gnu/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\0L\0\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0644, st_size=169960, ...}) = 0
mmap2(NULL, 179612, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7ebe000
mmap2(0xb7ee7000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0xb7ee7000
mmap2(0xb7ee9000, 3484, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7ee9000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/i386-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\3\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\20\220\1\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1942840, ...}) = 0
mmap2(NULL, 1948188, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7ce2000
mprotect(0xb7eb7000, 4096, PROT_NONE) = 0
mmap2(0xb7eb8000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1d5000) = 0xb7eb8000
mmap2(0xb7ebb000, 10780, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7ebb000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/i386-linux-gnu/libpcre.so.3", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\360\16\0\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0644, st_size=480564, ...}) = 0
mmap2(NULL, 483512, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7c6b000
mmap2(0xb7ce0000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x74000) = 0xb7ce0000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/i386-linux-gnu/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\320\n\0\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0644, st_size=13796, ...}) = 0
mmap2(NULL, 16500, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7c66000
mmap2(0xb7c69000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0xb7c69000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/i386-linux-gnu/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\300P\0\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=142820, ...}) = 0
mmap2(NULL, 123544, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7c47000
mmap2(0xb7c62000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1a000) = 0xb7c62000
mmap2(0xb7c64000, 4760, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7c64000
close(3) = 0
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7c45000
set_thread_area({entry_number=-1, base_addr=0xb7c45780, limit=0x0fffff, seg_32bit=1, contents=0, read_exec_only=0, limit_in_pages=1, seg_not_present=0, useable=1}) = 0 (entry_number=6)
mprotect(0xb7eb8000, 8192, PROT_READ) = 0
mprotect(0xb7c62000, 4096, PROT_READ) = 0
mprotect(0xb7c69000, 4096, PROT_READ) = 0
mprotect(0xb7ce0000, 4096, PROT_READ) = 0
mprotect(0xb7ee7000, 4096, PROT_READ) = 0
mprotect(0x469000, 4096, PROT_READ) = 0
mprotect(0xb7f2d000, 4096, PROT_READ) = 0
munmap(0xb7eea000, 89915) = 0
直到这里完全符合我自己的输出,但剩余的系统调用从未出现在我的程序中。这就是问题所在。我希望有人知道答案:P如果您有任何问题,请提出!
set_tid_address(0xb7c457e8) = 9767
set_robust_list(0xb7c457f0, 12) = 0
rt_sigaction(SIGRTMIN, {sa_handler=0xb7c4baf0, sa_mask=[], sa_flags=SA_SIGINFO}, NULL, 8) = 0
rt_sigaction(SIGRT_1, {sa_handler=0xb7c4bb80, sa_mask=[], sa_flags=SA_RESTART|SA_SIGINFO}, NULL, 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0
ugetrlimit(RLIMIT_STACK, {rlim_cur=8192*1024, rlim_max=RLIM_INFINITY}) = 0
uname({sysname="Linux", nodename="p200300D053D7310F22107AFFFE01D58C", ...}) = 0
statfs("/sys/fs/selinux", 0xbffeddb4) = -1 ENOENT (No such file or directory)
statfs("/selinux", 0xbffeddb4) = -1 ENOENT (No such file or directory)
brk(NULL) = 0x220c000
brk(0x222d000) = 0x222d000
brk(0x222e000) = 0x222e000
openat(AT_FDCWD, "/proc/filesystems", O_RDONLY|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
read(3, "nodev\tsysfs\nnodev\trootfs\nnodev\tr"..., 1024) = 401
read(3, "", 1024) = 0
close(3) = 0
brk(0x222d000) = 0x222d000
access("/etc/selinux/config", F_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=3365136, ...}) = 0
mmap2(NULL, 2097152, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7a45000
close(3) = 0
ioctl(1, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, TIOCGWINSZ, {ws_row=48, ws_col=198, ws_xpixel=0, ws_ypixel=0}) = 0
openat(AT_FDCWD, ".", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_CLOEXEC|O_DIRECTORY) = 3
fstat64(3, {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
getdents64(3, /* 3 entries */, 32768) = 80
getdents64(3, /* 0 entries */, 32768) = 0
close(3) = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
write(1, "test.py\n", 8test.py
) = 8
close(1) = 0
close(2) = 0
exit_group(0) = ?
+++ exited with 0 +++
最佳答案
如果您只寻找int 0x80
,您将错过使用sysenter
指令进行的正常32位系统调用(通常通过 glibc 调用 VDSO 页面)。 https://blog.packagecloud.io/eng/2016/04/05/the-definitive-guide-to-linux-system-calls/。 (同样在旧的 AMD CPU 上,32 位 syscall
也是可能的,如果它们太旧而无法支持 sysenter
,则可能默认使用。)
我想早期的 ld.so 代码使用遗留的 int 0x80
机制而不是调用 VDSO。 (这是有道理的;VDSO 将自己呈现为 一个映射到内存中的 ELF 共享对象;直到动态链接器将函数指针设置到其中,它才能使用它。)
64 位模式更简单:对于 64 位 ABI,一切都使用 syscall
。
请注意,在指令执行之前或之后检查机器代码可能会被试图隐藏在您的跟踪之外的代码欺骗。第二个线程可能会在您查看机器代码字节后交叉修改它,在它执行之前。 (也许让一个线程存储一个标志,这将导致另一个线程在它注意到时立即存储。如果时机合适,这可能会在您的 ptrace 提取和执行下一个单步之间潜伏。)
strace
(或沙盒/系统调用日志记录或代码过滤工具可能试图欺骗它)在 64 位模式下试图弄清楚是调用了 32 位还是 64 位 ABI(因为调用号不同)。 Can ptrace tell if an x86 system call used the 64-bit or 32-bit ABI?(或者曾经是,直到 Linux 内核 5.3 添加了 PTRACE_GET_SYSCALL_INFO
)。
是可以在 64 位代码中调用 int 0x80
,即使它基本上不是一个好主意:What is the explanation of this x86 Hello World using 32-bit int 0x80 Linux system calls from _start? 有一些关于内核端发生的事情的细节系统调用。
同样,只有当您关心试图从您的跟踪器中混淆其事件的程序时,这才是一个问题,例如作为反调试措施。让另一个线程覆盖正在执行的代码不会偶然发生。但在设计调试/跟踪工具时需要注意这一点。
如果将此代码用作库,那么有人可能会尝试从中构建沙盒系统调用过滤器,那么真正的危险就来了。例如检查所有文件访问系统调用中的路径,或拒绝未以只读方式打开的 open
调用。那么逃避追踪就成了一个真正的安全问题。 (当然,一般来说还有更好的沙盒方法。)
关于python - 使用自己的 python 调试器获取系统调用时遇到问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60439155/
我对 c# 有点陌生,我在尝试围绕这个 if-then 语句尝试实现时遇到了一些麻烦。 这是我的目标:当用户将订单输入系统时,将为每个订单创建一个唯一的 orderID。但是,一些附加功能是用户可以选
我已经搜索了这个特定的错误,发现根本问题涉及循环计数错误并导致程序超出数组的界限。 但是,当我将每个数组降低到数组开始丢失输出数据的程度后,它继续抛出相同的错误。我对 C/C++ 仍然是新手,但任何对
我不明白为什么我运行这个小程序时屏幕上没有任何显示? while 循环甚至开始了吗? #include #include int main() { char word[20]; char
我接手了一个用 Perl 编写的项目,它有一些依赖项,例如 Template::Toolkit , Image::ExifTool , 和 GD仅举几例。目前,这些依赖项使用 --prefix 构建到
我想对一个字段进行累积总和,但只要遇到 0 就重置聚合值。 这是我想要的一个例子: data.frame(campaign = letters[1:4] , date=c("jan","
不久前,该项目的 gradle 构建运行良好,但现在一直失败并显示以下错误(带有 --info 标志的输出): Starting process 'Gradle Test Executor 1'. W
我是编程新手,想用 Java 制作一个掷骰子程序来执行。代码如下: import java.math.*; public class Dices { public static int dice1=0
这个问题已经有答案了: What is a StringIndexOutOfBoundsException? How can I fix it? (1 个回答) 已关闭 5 年前。 我对 Java 完
这个方法一直抛出标题中的异常,我找不到原因,我已经通过连接创建了其他表,并且所有引用的表都已创建。我正在使用嵌入式JavaDB . private void createEvidenceTable()
我刚开始上课,这是我第三次尝试上课。我遇到了一个 NameError,我真的不知道如何解决。看看我的程序,看看你能不能帮忙。 import random import math import pyga
好吧,这是我的困境,我向 JFrame 添加了三个面板。第一个(不可见)第二个(可见)和第三个(不可见)..我使用第一个面板作为菜单,当您选择一个选项时,第一个面板被制作(可见),然后第三个面板被制作
我的部分代码遇到问题。如果我选择选项 A,它会运行并给我正确的答案,但是,如果我选择选项 S 或 M,它不会给我任何结果,只会去到它应该去的地方。已经尝试将 if 更改为 else if,但它显示“预
我这里有一些代码,但我正在努力解决它,因为我似乎无法掌握这个文件指针的东西。我对使用文件还很陌生。我见过类似的其他问题,并且尝试了对其他人有效的解决方案,但由于某种原因它们对我不起作用。这是出现问题的
我们有一个很大的应用程序,我们已经将 TODO 规则添加到质量门中,如果发现 TODO 注释,它会给出错误。如果我们只是删除 TODO 注释(这很可怕),它会起作用,但添加 TODO 注释的整个目的就
我正在尝试编写一个名为 isVowel 的函数,它接受一个字符(即长度为 1 的字符串)并在它是元音、大写或小写时返回“true”。如果该字符不是元音字母,该函数应返回“false”。 这看起来应该可
我一直在努力完成我正在做的这个小项目,但由于某种原因它无法正常工作。 问题是当我第一次访问该页面并单击出现在主要部分中的第一个链接时,它会根据需要显示弹出框。现在,当我点击另一天,例如星期天并尝试点击
我正在尝试制作一个 WPF 应用程序。我的窗口内有一个数据网格。我制作了另一个窗口,将新数据添加到我的数据网格中。虽然它按照我想要的方式工作,但我不断遇到异常。我的 MySQL 代码: using S
我试图在我似乎无法使 NSUserDefaults 正常工作的程序中保存几个首选项。如果有人可以查看我的代码并查看是否有任何错误,我们将不胜感激 NSString *kGameIsPaused = @
设置 SymmetricDS版本是3.9.1(也试过3.9.0) 设置是从 postgres 9.5.3 到 postgres 9.5.3 Windows 10 pc(客户端节点)到 Windows
经过长时间的努力,我终于(差不多)完成了我的java菜单程序。但是,我无法让我的返回更改功能在我的代码末尾工作。它给出了非常奇数的数字。有什么想法吗? 代码: import java.io.*; im
我是一名优秀的程序员,十分优秀!