protected,你真的理解了吗?

本文深入解析Java中的protected访问控制修饰符,通过多个示例代码详细阐述了protected成员在不同类和包之间的访问规则,包括继承访问与非继承访问的区别。

Java中的访问控制修饰符有四个级别,但属protected最复杂。如果问大家,protected修饰符作用,大家会说“在子类与同包中可以访问这个成员”,当然在自己类中也是可的,但你真的理解了吗?不信,先看看下面这些实例,看你是否也是这样想的(其中注释掉的是不能编译的,大家最好把这些代码放在eclipse中再看,不然你会晕的^_^):

package pk1.a;
public class Base {
	protected int i = 1;
	protected void protect() {
		System.out.println("Base::protect");
	}
}

package pk1.a;
import pk1.b.Sub;
public class SubSub extends Sub {
	void g() {
		Sub s = new SubSub();
		//!! s.protect();//规则2.c.i
		System.out.println(s.i);//规则2.c.ii
	}
}

package pk1.b;
import pk1.a.Base;
public class Sub extends Base {
	private void prt() {}
	protected void protect() {
		System.out.println("Base::protect");
	}
	void f() {
		//规则2.a
		this.protect();
		this.i = 2;

		//规则2.b
		Base a2 = new Sub();
		//!! a2.protect();
		//!! System.out.println(a2.i);

		//规则1
		Sub b = new Sub();
		b.protect();
		b.i = 1;
		b.prt();
	}
}

package pk1.b;
public class SubSub extends Sub {
	void g() {
		Sub s = new SubSub();
		s.protect();//规则2.c.i
		//!! System.out.println(s.i);//规则2.c.ii
	}
}

package pk1.c;
import pk1.a.Base;
import pk1.b.Sub;
public class SubSub extends Sub {
	void g() {
		this.protect();//规则2.a

		//规则2.b
		Base b = new SubSub();
		//!! b.protect();
		//!! System.out.println(b.i);

		//规则2.b
		Sub s = new SubSub();
		//!! s.protect();
		//!! System.out.println(s.i);

	}
}

 

package pk2.a;
public class Base {
	protected int i = 1;

	protected void protect() {
		System.out.println("Base::protect");
	}
}

package pk2.a;
import pk2.b.Sub;
public class Other {
	void g() {
		//规则3.a
		Base b = new Sub();
		b.protect();
		System.out.println(b.i);

		//规则3.b.ii
		Sub s = new Sub();
		s.protect();
		System.out.println(s.i);
	}
}

package pk2.b;
import pk2.a.Base;
public class Other {
	void g() {
		//规则3.a
		Base b = new Sub();
		//!! b.protect();
		//!! System.out.println(b.i);

		//规则3.b.ii
		Sub s = new Sub();
		//!! s.protect();
		//!! System.out.println(s.i);
	}
}

package pk2.b;
import pk2.a.Base;
public class Sub extends Base {}

 

package pk3.a;
import pk3.b.Sub;
public class Base {
	protected int i = 1;
	protected void protect() {
		System.out.println("Base::protect");
	}
	
	static protected int i_s = 1;
	static protected void protect_s() {
		System.out.println("Static:Base::protect");
	}
	
	void f() {
		//!! Sub.i_s = 2; //规则3.b.i
		Sub.protect_s();//规则3.b.ii
	}
}

package pk3.a;
import pk3.b.Sub;
public class Other {
	void g() {
		Sub s = new Sub();
		//!! s.protect();//规则3.b.i
		System.out.println(s.i);//规则3.b.ii
	}

	void f() {

		//!! Sub.i_s = 2; //规则3.b.i
		Sub.protect_s();//规则3.b.ii

		Base.i_s = 2;//规则3.a
		Base.protect_s();//规则3.a

	}
}

package pk3.b;
import pk3.a.Base;
public class Other {
	void f() {
		Sub.i_s = 2;//规则3.b.i
		//!! Sub.protect1();//规则3.b.ii
		
		//!! Base.i1 = 2;//规则3.a
		//!! Base.protect1();//规则3.a
	}
}

package pk3.b;
import pk3.a.Base;
public class Sub extends Base {
	protected void protect() {
		System.out.println("Base::protect");
	}
	static protected int i_s = 2;

	void f() {
		
		/*
		 * 在子类中可能通过子类类型或父类类型来来访问父类中protected静态
		 * 成员,而不管子类与父类是否在同一包中,或是子类重新定义了这些成员
		 * 
		 * 注,在父类或子类中访问时后面的规则不再适用
		 */
		System.out.println(Sub.i_s);//2
		Sub.protect_s();
	
		System.out.println(Base.i_s);//1
		Base.protect_s();
	}
}

 

如果你看到这里,想法与程序一致的话,说明你理解了,如果不理解,那看看我的理解吧:

 

定义规则前,我这里约定有三个类,一个是Base类,一个是Base类的子类Sub类,一个是Sub类的子类SubSub类,另一个是Other类且与BaseSubSubSub没有继承关系,并假设Base中有protected方法与属性,都叫YYY吧。

 

在理解protected规则:首先要搞清楚什么叫访问?这里在讲到的访问是有二种的:

一、就是在类中通过“XXX x = new XXX(); x.YYY;”的形式来访问(不妨叫此种形式为“外部访问”吧,此种访问形式除了可以应用到自己与子类中外,还可以应用在其他类中访问,其中XXX表示定义的类型,这里可为BaseSubSubSubYYY为方法或属性);

二、就是this.YYY的形式来访问(不妨叫此种形式为“内部访问”吧,不过这种访问形式只能应用在在自己的类或是子类中)。

 

protected方法与属性可访问的地方有三个:

1.         在自己的类Base中:上面的“XXX x = new XXX(); x.YYY;”与“this.YYY”两种访问形式都可以访问的到自己定义的portected方法或属性;

2.         二是子类SubSubSub中,这要分三种访问方式:

        a.         SubSubSub 中的“this.YYY”内部访问形式:在此种方式形式下,不管是否重写或重新定义过父类Baseprotected方法与属性,子类SubSubSub一定可以访问的。

        b.         SubSubSub 中“Base x = new XXX (); x.YYY;”外部访问形式:此种形式就不一定的能访问的到了,这要看父类Base与子类SubSubSub是否在同一包(注意,此时与是否重写或重新定义过这些protedted方法与属性没有关系);

        c.         SubSub 中“Sub x = new XXX (); x.YYY; 外部访问形式:此种访问形式能否访问关键看Sub是否重写或重新定义过Base的属性与方法:

                      i.              如果重写或重新定义过,则看SubSubSub是否在同包中

                      ii.             如果没有,则看BaseSubSub是否在同包中

3.         在其他类Other中:此时只支持外部访问形式,不过到底是要求OtherBase同包还是要求OtherSub同包,则要依你访问方式而定了:

        a.         如果是通过父类引用“Base x = new XXX (); x.YYY;”形式来访问的,则要求OtherBase同包;

        b.         如果是通过子类引用“Sub x = new Sub (); x.YYY;”形式来访问的,情况又会比较复杂了,此时关键是看子类Sub是否重写或重新定义过父类Base中的protected方法与属性:

                      i.              如果重写或重新定义过了,则要求OtherSub同包即可;

                      ii.             如果没有重写或重新定义过了,则要求OtherBase同包即可;

 

 

另外,写到这里我想到了Object中的clone方法,为什么要求具有克隆能力的类要求实现Cloneable接口与clone方法呢:Object.clone()访问修饰符为protected,如果某个类没有重写此方法,则Object中的clone()方法除被自己与子类能调用方法外,其他不管与这个类在同一包还是不同包都是不可见的,因为未重写,还是属于Object中的方法,又Objectjava.lang包中,与我们定义的包又不在java.lang包中,所以不能访问到(这也与你在在程序里定义了Object o = new Object();你还是不能在当前类中调用o.clone();一样),这也恰好符合上面 3.b.ii 这条规则。所以如果要能被不同包中的非子类克隆,则需重写Object.clone()并设置访问权限为public(如果重写后还是protected,则还是只能被同一包访问)。

 

以上这些就是我对protected限制的一种理解,肯定还有遗漏的地方,希望大家给我指出来,我来完善它。如果对你有帮助,请支持一下!

 

刚刚发现的一个小问题,一并附上《protected,这个错了吗?》

 

非常感谢大家,看了一下大家的理解,我上面的理解确实比较复杂,这正是因为把继承访问与非继承访问混在一起了就复杂了。其实这么理解就最简单了,还是以那句话,protected修饰的成员只允许子类与包访问!只不过子类可访问是指继承访问,即在子类的实例中直接访问继承过来的protected成员,而不是在子类中通过创建父类实例的方式来访问;而包访问就是指通过“XXX x = new XXX(); x.YYY;”的方式来访问,即通过实例的引用来访问,能不能访问就是看访问的代码所在的类是否与类XXX 在同一包中。但包访问要注意一点的是:如果XXX中只是继承了父类中的protected成员,而没有重写(方法)或重新定义(属性)这些成员,则能不能访问就要看当前访问的代码所在的类是否与类XXX的父类在同一包;另外如果类XXX重写与重新定义过这些protected成员,则就直接看访问代码所在的类与类XXX是否在同一包即可。

最后要注意的是静态的受保护成员比较特殊,因为protected static 成员即使被子类重写(严格的讲不叫重写)或重新定义后,还是会被继承下来,即在子类会有两份这样的static protected成员,只是他们的所属域(类)不同而已,所以在子类中可以通过父类的类型来访问所属于父的这些成员而不管子类与否与父类在同一包中,这与非静态的是不一样的。

 

 补充:方法能重写,属性能重写吗

<think>好的,用户想了解如何使用Windbg调试具有Protected完整性的进程。首先,我需要回顾一下之前关于Protected完整性和High完整性的区别。Protected完整性进程受内核级保护,阻止非受信进程的调试和内存访问,即使有管理员权限也无法轻易绕过。而High完整性是用户模式的最高权限,但可能仍然无法操作Protected进程。用户的问题涉及使用Windbg调试这类受保护的进程。根据之前的引用,SeDebugPrivilege权限在调试工具中是必需的,比如WinDbg附加到目标进程时需要此权限。但Protected进程可能有额外的保护机制,例如进程保护标志(如PROTECTION_LEVEL_WINTCB_LIGHT),这需要更高权限或特殊方法才能绕过。引用[1]提到SeDebugPrivilege用于调试工具和安全研究,但Protected进程可能阻止调试器附加。引用[2]中的DebugActiveProcess和CreateProcess的DEBUG_PROCESS标志是调试API的一部分,可能在此过程中使用。引用[3]指出Windbg作为原生调试器可能需要加载扩展模块(如sos)来支持某些情况,但不确定是否适用于Protected进程。 接下来,我需要整理步骤:首先,确保调试环境具备足够权限,如启用SeDebugPrivilege;可能需要以SYSTEM权限运行Windbg,因为管理员权限可能不足。然后,考虑加载内核驱动或使用特殊参数绕过保护,例如使用“-pvr”参数强制附加。此外,修改注册表或使用工具如ProcessExplorer临时禁用保护可能有效,但需注意系统稳定性。 还要注意,某些Protected进程(如WindowsDefender)可能在内核模式有额外保护,可能需要更高级的技术,如内核调试或使用Microsoft的符号服务器。需要提醒用户注意法律和系统安全,避免滥用这些方法。最后,生成相关问题,涉及调试技巧、绕过保护的方法、权限提升等,帮助用户深入理解。</think>### 如何使用Windbg调试Protected完整性进程 #### 1. **调试环境准备** - **以SYSTEM权限运行Windbg**: Protected进程通常禁止用户模式调试器附加,需通过内核级权限操作。 使用管理员权限打开命令提示符,执行: ```bash psexec -s -i windbg.exe # 通过Sysinternals工具获取SYSTEM权限[^1] ``` 数学表达:若进程$P$的完整性级别为$I_P$且满足$I_P \geq High$,则调试器$D$需满足$I_D = SYSTEM$[^1]。 - **启用SeDebugPrivilege权限**: 在Windbg命令窗口输入: ``` !process -1 0 # 查看当前进程权限 !token -e SeDebugPrivilege # 启用调试权限[^1] ``` #### 2. **绕过进程保护机制** - **强制附加进程**: 使用Windbg的`-pvr`参数强制附加到Protected进程(需内核支持): ```bash windbg -pv -pd -pn "ProtectedProcess.exe" # -pv: 忽略保护验证,-pd: 调试子进程[^2] ``` $$ \text{调试器附加成功条件}:\exists \, hProcess \in \text{DebugActiveProcess}(PID) \, \land \, \text{ProtectionLevel} \neq \text{WinTcb} $$ - **修改进程保护标志(高风险)**: 使用内核驱动临时修改目标进程的`EPROCESS.Protection`字段: ```c // 内核驱动示例(需签名) NTSTATUS DisableProtection(PEPROCESS TargetProcess) { PsProtection protection = PsGetProcessProtection(TargetProcess); protection.Level = 0; // 清零保护级别 PsSetProcessProtection(TargetProcess, protection); return STATUS_SUCCESS; } ``` > **警告**:此操作可能导致系统不稳定,且需禁用驱动签名强制(DSE)[^3]。 #### 3. **调试操作示例** - **附加到LSASS.exe(Protected进程)**: 1. 以SYSTEM权限运行Windbg并启用SeDebugPrivilege[^1] 2. 执行: ``` .attach <LSASS_PID> # 通过.process命令获取PID g # 继续执行 ``` 3. 若附加失败,尝试加载`kd.dll`扩展模块: ``` .load kd # 加载内核调试扩展 !process 0 0 LSASS.exe # 定位进程对象 !protect /disable <ProcessAddress> # 实验性命令(仅限测试环境)[^3] ``` #### 4. **调试限制与规避** | 场景 | 解决方案 | |----------------------|--------------------------------------------------------------------------| | **调试事件被过滤** | 使用`-d`参数启动Windbg(禁用初始断点)或Hook内核调试回调函数[^2] | | **内存访问被拒绝** | 通过`PHYSICAL`内存读写模式绕过虚拟内存保护:`!db PHYSICAL <Address>`[^2] | | **进程终止保护** | 注入APC(Asynchronous Procedure Call)到目标线程强制暂停[^1] | #### 5. **合法性与安全建议** - **仅限授权环境**:调试系统关键进程(如`csrss.exe`)需遵守微软EULA协议[^3]。 - **使用虚拟机环境**:避免对宿主机构成安全风险。 - **符号配置**:确保Windbg配置了Microsoft符号服务器: ``` .symfix C:\Symbols .reload ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值