去教育版戳记源码(ARX,LISP版)
highflybird
- 登录 发表评论
CAD教育版戳记有时候很讨厌,一旦图中有这个戳记,就会传染到其它图中。就是说从有戳记的图中拷贝到没戳记的,没戳记的也会带上。
而且这个戳记不太好消除。
对于2015-2018,Autodesk公司似乎已经把这个戳记移除掉了,也就是说,用这些版本的CAD打开图,看不到戳记,也不会弹出那个戳记警告框。
保存之后,图中不会再有了(这点我没有每个版本验证)。但该死的是到了2019后,这个又出现了,不知道autodesk公司在玩什么。
关于去教育版有很多方式,ARX的方式最有效。我这里提供用了ARX源码。以及附带的生成的ARX程序。
这个程序的源码 是从网上的 wdzhangsl 引申过来,特此深表感谢!
程序的原理是从数据库指针找到戳记的偏移地址,修改此处的值,便达到了消除。
因为原代码有些重复和繁琐,特此精简,并且升级到2019。经过测试,程序有效。
因为有些CAD版本我是没办法在自己机器安装,就没有一个个CAD版本进行测试其中的偏移地址。
如果有网友能测试到我程序中没有的CAD版本的值,请告诉我或者跟帖。多谢!
下面是程序的源码和已经编译好二进制文件的压缩包。欢迎各位捉虫子和提出建议。
程序的用法是:加载后,程序会自动消除戳记,也可以用手动输入命令QJYB 来消除。
如果你把此程序加载到启动组,以后每当打开有教育版的dwg后,程序会自动消除,你需要做的仅仅是保存文件而已。
对于LISp版本,更有这两项突出功能:
1、消除打开戳记文件的错误警告框。
2、全面兼容各种CAD版本。
LISP的代码如下:(需要DynamicWrapperX支持)
;|*************************************************************;
软件作者: Highflybird ;
软件用途: 消除CAD教育版戳记 ;
日期地点: 2019.05.12 深圳 ;
程序语言: AutoLISP,Visual LISP ;
版本号: Ver. 1.0.19.0512 ;
===============================================================;
================================================================
本软件为开源软件: 以下是开源申明:
----------------------------------------------------------------
本页面的软件遵照 GPL协议开放源代码,您可以自由传播和修改,在遵照
下面的约束条件的前提下:
一. 只要你在本开源软件的每一副本上明显和恰当地出版版权声明,保持
此许可证的声明和没有担保的声明完整无损,并和程序一起给每个其
他的程序接受者一份许可证的副本,你就可用任何媒体复制和发布你
收到的原始程序的源代码。你也可以为转让副本的实际行动收取一定
费用,但必须事先得到的同意。
二. 你可以修改本开源软件的一个或几个副本或程序的任何部分,以此形
成基于程序的作品。只要你同时满足下面的所有条件,你就可以按前
面第一款的要求复制和发布这一经过修改的程序或作品。
1.你必须在修改的文件中附有明确说明:你修改了这一文件及具体的修
改日期。
2.你必须使你发布或出版的作品(它包含程序的全部或一部分,或包含
由程序的全部或部分衍生的作品)允许第三方作为整体按许可证条款
免费使用。
3.如果修改的程序在运行时以交互方式读取命令,你必须使它在开始进
入常规的交互使用方式时打印或显示声明: 包括适当的版权声明和没
有担保的声明(或者你提供担保的声明);用户可以按此许可证条款
重新发布程序的说明;并告诉用户如何看到这一许可证的副本。(例
外的情况: 如果原始程序以交互方式工作,它并不打印这样的声明,
你的基于程序的作品也就不用打印声明。
三. 只要你遵循一、二条款规定,您就可以自由使用并传播本源代码,但
必须原封不动地保留原作者信息。
================================================================
**************************************************************|;
(defun c:QJYB (/ acdb addr DWX flag hMod isOK name pEMR pFlag
hPROC Code CADVer OFFSET PID pNEW VMAP)
(if (setq dwx (vlax-create-object "DynamicWrapperX"))
(progn
(DWX:Register DWX)
(setq acdb (strcat "acdb" (substr (getvar "acadver") 1 2) ".dll"))
(setq hMod (vlax-invoke DWX 'GetModuleHandle acdb))
(if (Is64Bit)
(setq Name "?isEMR@AcDbDatabase@@QEBA_NXZ"
pEMR (vlax-invoke DWX 'GetProcAddress hMod name)
vMap '((172 . "180B")
(180 . "800B")
(181 . "880B")
(182 . "900B")
(190 . "A80B")
(191 . "B00B")
(230 . "A00B")
(231 . "A00B")
(240 . "A00B")
(241 . "A00B")
)
)
(setq Name "?isEMR@AcDbDatabase@@QBE_NXZ"
pEMR (vlax-invoke DWX 'GetProcAddress hMod name)
vMap '((150 . "A406")
(160 . "D406")
(161 . "D406")
(162 . "D406")
(170 . "DC07")
(171 . "2408")
(172 . "3408")
(180 . "6C08")
(181 . "7408")
(182 . "7C08")
(190 . "8408")
(191 . "8408")
(230 . "8408")
)
)
)
(setq CADVer (fix (* 10 (atof (substr (getvar "acadver") 1 4)))))
(setq offset (cdr (assoc CADVer vMap)))
(setq Func (read name))
(if (zerop pEMR)
(princ "\n你运行的CAD版本可能是2015-2018,它会自动消除教育版!")
(if
(and
(/= 0 (setq pID (vlax-invoke DWX 'GetCurrentProcessId)))
(/= 0 (setq hProc (vlax-invoke DWX 'OpenProcess 2035711 0 pID))) ;2035711 = PROCESS_ALL_ACCESS = 0x1F0FFF;
)
(progn
;(FindOffset DWX acdb name)
(if (Is64Bit)
(setq Code (strcat "488B490833C08981" offset "00003C00C3"))
(setq Code (strcat "8B490433C08981" offset "00003C00C3"))
)
(setq pFlag (vlax-invoke DWX 'MemAlloc 4))
(setq isOK (vlax-invoke DWX 'VirtualProtect pEMR 30 4 pFlag)) ;PAGE_READWRITE = 0x4;
(if (/= isOK 0)
(setq pNew (vlax-invoke DWX 'MemWrite Code pEMR)
flag (vlax-invoke DWX 'NumGet pFlag)
isOK (vlax-invoke DWX 'VirtualProtect pEMR 30 flag pFlag)
)
)
(vlax-invoke DWX 'MemFree pFlag)
(vlax-invoke DWX 'CloseHandle hProc)
(if (zerop isOK)
(princ "\n程序运行失败!")
(princ "\n程序运行成功!")
)
)
)
)
)
(princ "\n你没有注册DynamicWrapperX!或者没有权限!")
)
(princ)
)
;;; (setq code "55 8BEC 81ECC 0000000 53 56 57 8DBD 40FFFFFF B9 30000000 B8CCCCCCCC F3AB A1F4 C9FF07 8B00 5F 5E 5B 8BE5 5D C3")
;;; (setq pCode (vlax-invoke DWX 'MemAlloc (/ (strlen code) 2) 1))
;;; (vlax-invoke DWX 'RegisterCode code "GetApp" "r=p")
;;;=============================================================
;;; 功能: 寻找教育版戳记的偏移地址
;;; 输入: 十进制整数。
;;; 输出: 十六进制数,用字符串表示。
;;;=============================================================
(defun FindOffset (DWX acdb name / I offset pSVR pDB mpImpDb oldV)
(vlax-invoke DWX 'Register acdb "?acdbHostApplicationServices@@YAPEAVAcDbHostApplicationServices@@XZ" "r=p")
(vlax-invoke DWX 'Register acdb name "i=p" "r=l")
(setq pSVR (vlax-invoke DWX '?acdbHostApplicationServices@@YAPEAVAcDbHostApplicationServices@@XZ))
(setq pDB (vlax-invoke DWX 'NumGet pSVR 16))
(setq mpImpDb (vlax-invoke DWX 'NumGet pDB 8)) ;mpImpDb
(setq i 1536);0x600
(while (and (zerop (vlax-invoke DWX name pDB)) (< i 4096))
(setq oldv (vlax-invoke DWX 'NumGet mpImpDb i))
(if (/= oldv 1)
(progn
(vlax-invoke DWX 'NumPut 1 mpImpDb i)
(if (/= 0 (vlax-invoke DWX name pDB))
(setq offset i)
(vlax-invoke DWX 'NumPut oldv mpImpDb i)
)
)
)
(setq i (1+ i))
)
(if offset
(progn
(vlax-invoke DWX 'NumPut 0 mpImpDb offset)
(DWX:HEX2CODE (DWX:DEC2HEX offset))
)
)
)
;;;(setq *app (vlax-get-acad-object))
;;;(setq strAPp (VL-PRINC-TO-STRING *app))
;;;(setq *doc (vla-get-ActiveDocument *app))
;;;(setq ppp (vlax-invoke DWX 'MemAlloc 8 1))
;;;(vlax-invoke DWX 'MemWrite (substr strapp 31 8) ppp)
;;;(vlax-invoke DWX 'NumGet ppp)
;;;=============================================================
;;; 功能: 十进制转16进制
;;; 输入: 十进制整数。
;;; 输出: 十六进制数,用字符串表示。
;;;=============================================================
(defun DWX:DEC2HEX (x / h v y)
(setq h "")
(if (= 'int (type x))
(if (zerop x)
(setq h "0")
(while (< 0 x)
(setq y (rem x 16)
x (/ x 16)
v (if (> y 9)
(chr (+ y 55))
(itoa y)
)
h (strcat v h)
)
)
)
)
)
;;;=============================================================
;;; 功能: 将16进制数转化为机器码
;;; 输入: 16进制数(字符串)
;;; 输出: 机器码。
;;;=============================================================
(defun DWX:HEX2CODE (s / l)
(if (= 1 (rem (strlen s) 2))
(setq s (strcat "0" s))
)
(setq l "")
(while (/= s "")
(setq l (strcat (substr s 1 2) l))
(setq s (substr s 3))
)
l
)
;;;=============================================================
;;; 功能: 检查CAD是否为64位。
;;; 输入: 无。
;;; 输出: CAD如果是64位则返回T,否则返回nil。
;;;=============================================================
(defun Is64Bit ()
(= 27 (strlen (VL-PRINC-TO-STRING +)))
)
;;;=============================================================
;;; 功能: 注册一些与内存相关函数
;;; 输入: DynamicWrapperX对象。
;;; 输出: 无。
;;;=============================================================
(defun DWX:Register (DWX)
(vlax-invoke DWX 'Register "KERNEL32" "LoadLibrary" "i=s" "r=p")
(vlax-invoke DWX 'Register "KERNEL32" "FreeLibrary" "i=p" "r=l")
(vlax-invoke DWX 'Register "KERNEL32" "GetCurrentProcessId" "r=l")
(vlax-invoke DWX 'Register "KERNEL32" "OpenProcess" "i=lll" "r=p")
(vlax-invoke DWX 'Register "KERNEL32" "VirtualProtect" "i=pllp" "r=l")
(vlax-invoke DWX 'Register "KERNEL32" "VirtualProtectEx" "i=hpllp" "r=l")
(vlax-invoke DWX 'Register "KERNEL32" "VirtualQueryEx" "i=hppl" "r=l")
(vlax-invoke DWX 'Register "KERNEL32" "ReadProcessMemory" "i=hpplp" "r=l")
(vlax-invoke DWX 'Register "KERNEL32" "WriteProcessMemory" "i=hpplp" "r=l")
(vlax-invoke DWX 'Register "KERNEL32" "GetProcAddress" "i=hs" "r=p")
(vlax-invoke DWX 'Register "KERNEL32" "GetModuleHandle" "i=s" "r=h")
(vlax-invoke DWX 'Register "KERNEL32" "GetLastError" "r=l")
(vlax-invoke DWX 'Register "KERNEL32" "CloseHandle" "i=h" "r=l")
)
(vl-load-com)
(princ "\n帮助说明: 程序运行命令是QJYB。注意: 请运行在打开有教育版戳记的图形前!!! ")
(princ "\n命令运行一次后无需再输入,程序会自动消除教育版戳记了,你只需保存图即可。")
(princ "\n如果你希望每次都能用,请加载到启动组。")
(princ)ARX的核心代码如下:
#include "stdafx.h"
#include "GetProcess.h"
#include "GetFunctionAddress.h"
#include "RemoveEDU.h"
byte OffsetAddress32[6][6]={
{0xa4,0x06,0xa4,0x06,0xa4,0x06},//R15
{0xd4,0x06,0xd4,0x06,0xd4,0x06},//R16
{0xdc,0x07,0x24,0x08,0x34,0x08},//R17
{0x6c,0x08,0x74,0x08,0x7c,0x08},//R18
{0x84,0x08,0x84,0x08,0x84,0x08},//R19
{0x84,0x08,0x84,0x08,0x84,0x08},//R23
};
byte OffsetAddress64[4][6]={
{0x18,0x0b,0x18,0x0b,0x18,0x0b},//R17
{0x80,0x0b,0x88,0x0b,0x90,0x0b},//R18
{0xa8,0x0b,0xb0,0x0b,0xb8,0x0b},//R19
{0xa0,0x0b,0xa0,0x0b,0xa0,0x0b},//R23
};
int RemoveEducationStamp(WNDINFO & wi)
{
if (wi.ActiveDoc==NULL)
return FALSE;
int ret = FALSE;
CAcadUtility uti=wi.ActiveDoc.get_Utility();
//获取isEMR函数的RVA地址
INT_PTR offsetAddr = 0;
LPCSTR funcName = wi.is64bit ? "?isEMR@AcDbDatabase@@QEBA_NXZ" : "?isEMR@AcDbDatabase@@QBE_NXZ";
HMODULE hDLL = LoadLibraryEx(wi.strAcDbPath,0,DONT_RESOLVE_DLL_REFERENCES);//
LPVOID pIsEMR = GetProcAddress(hDLL,funcName);
FreeLibrary(hDLL);
if (pIsEMR == NULL)
{
pIsEMR = LoadFuncBase(wi.strAcDbPath,funcName,hDLL);
}
if (pIsEMR == NULL)
{
FUNCTION_ADDRESS funcSet;
ret = getFuncAddr(wi.strAcDbPath,funcSet);
FUNCTION_ADDRESS::iterator itr = funcSet.find(funcName);
if (itr == funcSet.end())
{
uti.Prompt(_T("找不到教育版相关函数!可能需要以管理员身份运行此程序,或者CAD版本是2015-2018.\n"));
return FALSE;
}
offsetAddr = itr->second;
pIsEMR = LPVOID((INT_PTR)wi.hAcDb + offsetAddr); //操纵数据库
}
else
{
offsetAddr = (INT_PTR)pIsEMR - (INT_PTR)hDLL;
pIsEMR = LPVOID((INT_PTR)wi.hAcDb + offsetAddr); //操纵数据库
}
//以写的方式打开CAD进程
//HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, wi.dwProcessId); //权限要求太高,可能在某些机器上运行不了
HANDLE hProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_QUERY_INFORMATION | PROCESS_VM_WRITE, FALSE, wi.dwProcessId);
if (hProcess == NULL)
{
uti.Prompt(_T("无法打开CAD进程写入!\n"));
return FALSE;
}
const DWORD bWritten = 128;
byte pEAX = 0;
SIZE_T dwNumberOfBytes = 0;
CString strTemp = wi.strVersion.Mid(1,2);
int nMajorVersion = _ttoi(strTemp.GetBuffer());
if (nMajorVersion>22)
nMajorVersion-=3;
strTemp = wi.strVersion.Mid(4,1);
int nMinorVersion = _ttoi(strTemp.GetBuffer());
if (wi.is64bit)
{
byte AsmCode[15] = {0x48,0x8B,0x49,0x08,0x33,0xC0,0x89,0x81,0x00,0x00,0x00,0x00,0x3C,0x00,0xC3};
nMajorVersion = nMajorVersion-17;
AsmCode[8]=OffsetAddress64[nMajorVersion][2*nMinorVersion];
AsmCode[9]=OffsetAddress64[nMajorVersion][2*nMinorVersion+1];
ret = WriteProcessMemory(hProcess,pIsEMR,AsmCode,sizeof(AsmCode),&dwNumberOfBytes);
}
else
{
byte AsmCode[14] = {0x8B,0x49,0x04,0x33,0xC0,0x89,0x81,0x00,0x00,0x00,0x00,0x3C,0x00,0xC3};
nMajorVersion = nMajorVersion-15;
AsmCode[7]=OffsetAddress32[nMajorVersion][2*nMinorVersion];
AsmCode[8]=OffsetAddress32[nMajorVersion][2*nMinorVersion+1];
ret = WriteProcessMemory(hProcess,pIsEMR,AsmCode,sizeof(AsmCode),&dwNumberOfBytes);
}
if (!ret)
{
uti.Prompt(_T("修改内存模式失败!\n"));
}
else
{
wi.isRemoved = true;
}
CloseHandle(hProcess);
return ret;
}