Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/vba/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Vba 使用Apache POI检查Excel宏密码_Vba_Apache Poi - Fatal编程技术网

Vba 使用Apache POI检查Excel宏密码

Vba 使用Apache POI检查Excel宏密码,vba,apache-poi,Vba,Apache Poi,您能否检查Excel中的宏代码是否受密码保护,甚至验证哪个密码? 我确实找到了关于密码保护的Excel工作簿和受保护的工作表的示例,但没有找到关于锁定宏代码的示例。对于重新设计的Office文档,您可以使用my,以便轻松查看嵌入元素的结构和位置 信息存储在vbaProject.bin的PROJECT流中。 这是一个很好的例子。 使用以下代码可以验证DPB元素(项目密码) import org.apache.commons.codec.DecoderException; import org.a

您能否检查Excel中的宏代码是否受密码保护,甚至验证哪个密码?

我确实找到了关于密码保护的Excel工作簿和受保护的工作表的示例,但没有找到关于锁定宏代码的示例。

对于重新设计的Office文档,您可以使用my,以便轻松查看嵌入元素的结构和位置

信息存储在
vbaProject.bin
PROJECT
流中。 这是一个很好的例子。 使用以下代码可以验证
DPB
元素(项目密码)

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackagePartName;
import org.apache.poi.openxml4j.opc.PackagingURIHelper;
import org.apache.poi.poifs.crypt.CryptoFunctions;
import org.apache.poi.poifs.crypt.HashAlgorithm;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Properties;

public class VBAProtect {
    private static final String NO_PASSWORD_HASH = "0E0CD1ECDFF4E7F5E7F5E7";

    public static void main(String[] args) throws DecoderException, IOException, InvalidFormatException {
        try (FileInputStream is = new FileInputStream("vba-protected.xlsm");
             XSSFWorkbook wb = new XSSFWorkbook(is)) {
            PackagePartName pn = PackagingURIHelper.createPartName("/xl/vbaProject.bin");
            PackagePart part = wb.getPackage().getPart(pn);

            try (InputStream pis = part.getInputStream();
                 POIFSFileSystem ps = new POIFSFileSystem(pis);
                 InputStream dis = ps.createDocumentInputStream("PROJECT")) {

                Properties prop = new Properties();
                prop.load(dis);
                String DPB = prop.getProperty("DPB").replace("\"", "");

                if (NO_PASSWORD_HASH.equals(DPB)) {
                    System.out.println("no password");
                } else {
                    EncData ed = new EncData();
                    ed.parse(DPB);
                    PasswordHash ph = new PasswordHash();
                    ph.parse(ed);

                    String pass = "password";
                    System.out.println("pass <" + pass + "> matches? " + ph.matches(pass));
                }
            }
        }

    }

    public static class EncData {
        public byte seed;
        public byte version;
        public byte projKey;
        public int ignoredLength;
        public int dataLength;
        private byte[] raw;

        public byte[] getData() {
            byte[] data = new byte[dataLength];
            // Header (3 bytes) + Ignored bytes + length (4 bytes)
            System.arraycopy(raw, 3 + ignoredLength + 4, data, 0, dataLength);
            return data;
        }

        public void parse(String data) throws DecoderException {
            raw = Hex.decodeHex(data);
            seed = raw[0];
            byte VersionEnc = raw[1];
            byte ProjKeyEnc = raw[2];
            ignoredLength = ((seed & 6) / 2);

            version = (byte)((seed ^ VersionEnc) & 0xFF);
            projKey = (byte)((seed ^ ProjKeyEnc) & 0xFF);
            byte UnencryptedByte1 = projKey;
            byte EncryptedByte1 = ProjKeyEnc;
            byte EncryptedByte2 = VersionEnc;

            for (int offset = 3; offset < raw.length; offset++) {
                byte ByteEnc = raw[offset];
                byte Byte = (byte)((ByteEnc ^ (EncryptedByte2 + UnencryptedByte1)) & 0xFF);
                EncryptedByte2 = EncryptedByte1;
                EncryptedByte1 = ByteEnc;
                raw[offset] = UnencryptedByte1 = Byte;
            }

            dataLength = LittleEndian.getInt(raw, 3 + ignoredLength);
        }
    }

    public static class PasswordHash {
        public final byte[] key = new byte[4];
        public final byte[] passwordHash = new byte[20];

        public void parse(EncData data) {
            byte[] dpb = data.getData();
            // first byte of grbit is reserved, so ignore it
            int Grbit = LittleEndian.getInt(dpb, 0) >>> 8;
            final int offset = 4;
            for (int i=0; i<24; i++, Grbit >>>= 1) {
                if ((Grbit & 1) == 0) {
                    dpb[offset+i] = 0;
                }
            }
            System.arraycopy(dpb, offset, key, 0, 4);
            System.arraycopy(dpb, offset+4, passwordHash, 0, 20);
        }

        public boolean matches(String password) {
            // TODO: check MBCS windows encoding differences to UTF-8
            // https://stackoverflow.com/questions/3298569/difference-between-mbcs-and-utf-8-on-windows
            MessageDigest shaDig = CryptoFunctions.getMessageDigest(HashAlgorithm.sha1);
            shaDig.update(password.getBytes(StandardCharsets.UTF_8));
            shaDig.update(key);
            byte[] dig = shaDig.digest();
            return Arrays.equals(dig, passwordHash);
        }
    }
}
import org.apache.commons.codec.DecoderException;
导入org.apache.commons.codec.binary.Hex;
导入org.apache.poi.openxml4j.exceptions.InvalidFormatException;
导入org.apache.poi.openxml4j.opc.PackagePart;
导入org.apache.poi.openxml4j.opc.PackagePartName;
导入org.apache.poi.openxml4j.opc.PackagingURIHelper;
导入org.apache.poi.poifs.crypt.CryptoFunctions;
导入org.apache.poi.poifs.crypt.HashAlgorithm;
导入org.apache.poi.poifs.filesystem.poifsfsystem;
导入org.apache.poi.util.LittleEndian;
导入org.apache.poi.xssf.usermodel.xssf工作簿;
导入java.io.FileInputStream;
导入java.io.IOException;
导入java.io.InputStream;
导入java.nio.charset.StandardCharset;
导入java.security.MessageDigest;
导入java.util.array;
导入java.util.Properties;
公共类VBA保护{
私有静态最终字符串NO_PASSWORD_HASH=“0E0CD1ECDFF4E7F5E7F5E7”;
公共静态void main(字符串[]args)引发DecodeException、IOException、InvalidFormatException{
try(FileInputStream=newfileinputstream(“vba protected.xlsm”);
XSSF工作簿wb=新XSSF工作簿(is)){
PackagePartName pn=PackagingURIHelper.createPartName(“/xl/vbaProject.bin”);
PackagePart部分=wb.getPackage().getPart(pn);
try(InputStream pis=part.getInputStream();
POIFSFISTEM ps=新的POIFSFISTEM(pis);
InputStream dis=ps.createDocumentInputStream(“项目”)){
Properties prop=新属性();
道具载荷(dis);
字符串DPB=prop.getProperty(“DPB”)。替换(“\”,”);
if(无密码\u散列等于(DPB)){
System.out.println(“无密码”);
}否则{
EncData ed=新的EncData();
ed.parse(DPB);
PasswordHash ph=新的PasswordHash();
理学博士(教育);
字符串pass=“password”;
System.out.println(“通过匹配?”+ph.matches(通过));
}
}
}
}
公共静态类数据{
公共字节种子;
公共字节版本;
公共字节projKey;
公共输入信号长度;
公共int数据长度;
私有字节[]原始;
公共字节[]getData(){
字节[]数据=新字节[dataLength];
//标题(3字节)+忽略的字节+长度(4字节)
System.arraycopy(原始,3+忽略数据长度+4,数据,0,数据长度);
返回数据;
}
公共void解析(字符串数据)抛出DecoderException{
原始=十六进制。解码十六进制(数据);
种子=原始[0];
字节VersionEnc=raw[1];
字节projkeync=raw[2];
ignoredLength=((种子和6)/2);
版本=(字节)((种子^VersionEnc)和0xFF);
projKey=(字节)((种子^projkeync)和0xFF);
字节未加密字节1=projKey;
byte EncryptedByte1=ProjKeyEnc;
字节加密字节2=VersionEnc;
对于(int offset=3;offset>8;
最终整数偏移=4;
对于(int i=0;i>>=1){
如果((Grbit&1)==0){
dpb[offset+i]=0;
}
}
系统阵列复制(dpb,偏移量,键,0,4);
数组复制(dpb,偏移量+4,密码哈希,0,20);
}
公共布尔匹配(字符串密码){
//TODO:检查MBCS windows编码与UTF-8的差异
// https://stackoverflow.com/questions/3298569/difference-between-mbcs-and-utf-8-on-windows
MessageDigest shaDig=CryptoFunctions.getMessageDigest(HashAlgorithm.sha1);
update(password.getBytes(StandardCharsets.UTF_8));
shaDig.update(键);
字节[]dig=shaDig.digest();
返回数组.equals(dig,passwordHash);
}
}
}

对于重新设计的Office文档,您可以使用my,以便轻松查看嵌入元素的结构和位置

信息存储在
vbaProject.bin
PROJECT
流中。 这是一个很好的例子。 使用以下代码可以验证
DPB
元素(项目密码)

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackagePartName;
import org.apache.poi.openxml4j.opc.PackagingURIHelper;
import org.apache.poi.poifs.crypt.CryptoFunctions;
import org.apache.poi.poifs.crypt.HashAlgorithm;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Properties;

public class VBAProtect {
    private static final String NO_PASSWORD_HASH = "0E0CD1ECDFF4E7F5E7F5E7";

    public static void main(String[] args) throws DecoderException, IOException, InvalidFormatException {
        try (FileInputStream is = new FileInputStream("vba-protected.xlsm");
             XSSFWorkbook wb = new XSSFWorkbook(is)) {
            PackagePartName pn = PackagingURIHelper.createPartName("/xl/vbaProject.bin");
            PackagePart part = wb.getPackage().getPart(pn);

            try (InputStream pis = part.getInputStream();
                 POIFSFileSystem ps = new POIFSFileSystem(pis);
                 InputStream dis = ps.createDocumentInputStream("PROJECT")) {

                Properties prop = new Properties();
                prop.load(dis);
                String DPB = prop.getProperty("DPB").replace("\"", "");

                if (NO_PASSWORD_HASH.equals(DPB)) {
                    System.out.println("no password");
                } else {
                    EncData ed = new EncData();
                    ed.parse(DPB);
                    PasswordHash ph = new PasswordHash();
                    ph.parse(ed);

                    String pass = "password";
                    System.out.println("pass <" + pass + "> matches? " + ph.matches(pass));
                }
            }
        }

    }

    public static class EncData {
        public byte seed;
        public byte version;
        public byte projKey;
        public int ignoredLength;
        public int dataLength;
        private byte[] raw;

        public byte[] getData() {
            byte[] data = new byte[dataLength];
            // Header (3 bytes) + Ignored bytes + length (4 bytes)
            System.arraycopy(raw, 3 + ignoredLength + 4, data, 0, dataLength);
            return data;
        }

        public void parse(String data) throws DecoderException {
            raw = Hex.decodeHex(data);
            seed = raw[0];
            byte VersionEnc = raw[1];
            byte ProjKeyEnc = raw[2];
            ignoredLength = ((seed & 6) / 2);

            version = (byte)((seed ^ VersionEnc) & 0xFF);
            projKey = (byte)((seed ^ ProjKeyEnc) & 0xFF);
            byte UnencryptedByte1 = projKey;
            byte EncryptedByte1 = ProjKeyEnc;
            byte EncryptedByte2 = VersionEnc;

            for (int offset = 3; offset < raw.length; offset++) {
                byte ByteEnc = raw[offset];
                byte Byte = (byte)((ByteEnc ^ (EncryptedByte2 + UnencryptedByte1)) & 0xFF);
                EncryptedByte2 = EncryptedByte1;
                EncryptedByte1 = ByteEnc;
                raw[offset] = UnencryptedByte1 = Byte;
            }

            dataLength = LittleEndian.getInt(raw, 3 + ignoredLength);
        }
    }

    public static class PasswordHash {
        public final byte[] key = new byte[4];
        public final byte[] passwordHash = new byte[20];

        public void parse(EncData data) {
            byte[] dpb = data.getData();
            // first byte of grbit is reserved, so ignore it
            int Grbit = LittleEndian.getInt(dpb, 0) >>> 8;
            final int offset = 4;
            for (int i=0; i<24; i++, Grbit >>>= 1) {
                if ((Grbit & 1) == 0) {
                    dpb[offset+i] = 0;
                }
            }
            System.arraycopy(dpb, offset, key, 0, 4);
            System.arraycopy(dpb, offset+4, passwordHash, 0, 20);
        }

        public boolean matches(String password) {
            // TODO: check MBCS windows encoding differences to UTF-8
            // https://stackoverflow.com/questions/3298569/difference-between-mbcs-and-utf-8-on-windows
            MessageDigest shaDig = CryptoFunctions.getMessageDigest(HashAlgorithm.sha1);
            shaDig.update(password.getBytes(StandardCharsets.UTF_8));
            shaDig.update(key);
            byte[] dig = shaDig.digest();
            return Arrays.equals(dig, passwordHash);
        }
    }
}
import org.apache.commons.codec.DecoderException;
导入org.apache.commons.codec.binary.Hex;
导入org.apache.poi.openxml4j.exceptions.InvalidFormatException;
导入org.apache.poi.openxml4j.opc.PackagePart;
导入org.apach