取得系统中网卡MAC地址的三种方法 Z.mnD+{
网卡地址这个概念有点混淆不清。因为实际上有两个地址,mac地址和物理地址,一般说网卡地址我是指物理地址,不知道别人怎么看?物理地址指的是网卡上的存放地址的ROM里的地址,mac地址是这块卡工作的时候用的地址,一般情况下这两个地址是一样的,所以很多人都混用了,甚至不知道有区别 -_-# fa;GM7<e)
2s8(r8 AI
网卡工作的时候,一个以太网帧60到1514(不包括crc),帧的crc是网卡自动加的,前导码是自动加的。网卡目的地址和源地址是驱动程序加的.所以实际上网卡工作的时候用什么地址作为工作地址完全是由驱动程序决定的 :)因此,我们完全可以在不改变网卡的物理地址的情况下用软件方法改变具体的网卡的工作地址. 0%5x&vx'S
z,/y2H2
MAC地址一般保存在注册表里,可以修改,于是就有下面连个问题: M^~
l%9nA.M'
第1,可以肆无忌弹的盗用ip, b}jLI_R{
V39)[FH}
第2,可以破一些垃圾加密软件... ^1NtvQe@Y\
|cq%eN
很多软件是通过网卡地址加密的,这里面有两种不同。有些做的比较好的是通过物理地址加密。有些是通过工作地址加密.通过工作地址加密的像通过guidgen,netbios等方法得到的地址都是mac地址。一般都可以用该方法破解。通过物理地址加密的有点难破,但是也不是没有办法。 ^p!bteA>
w\3'wD!
Ow7I`#P
ti9cfv>
第一种方法使用Microsoft的Netbios API。 这是一套通过Winsock提供底层网络支持的命令。使用Netbios的最大缺点是您必须在系统中安装了Netbios服务(如果您在windows网络中启用了文件共享的话,这就不是问题了)。除此此外,这种方法又快又准确。 !YEU<9
G/C5o=cY
g@7j<UY
=Pgu?WU@
Netbios API只包括了一个函数,就叫做Netbios。这个函数使用网络控制块(network control block)结构作为参数,这个结构告诉函数要做什么。结构的定义如下: @DYkWivLu
m1lfC
typedef struct _NCB { YP vg(T
Y&_1U/}h
UCHAR ncb_command; blA]z!FU
L8j#lu
UCHAR ncb_retcode; bNO/CD4
6Bfu89
UCHAR ncb_lsn; @X6|[r&Z
>SZ9,K4Gs
UCHAR ncb_num; ^,KN@
WS)u{
or
PUCHAR ncb_buffer; O@bDMg
yD!V;?EnK
WORD ncb_length; J#y?^Qm$)<
ps6c>AN`A&
UCHAR ncb_callname[NCBNAMSZ]; u3H2\<
`?L-{VtM3*
UCHAR ncb_name[NCBNAMSZ]; VClw!bm
SAGLLk07G
UCHAR ncb_rto; 8M;G@ Q80
_[W`!#"
UCHAR ncb_sto; 0\y@etb:mf
3fJwj}wL
void (CALLBACK *ncb_post) (struct _NCB *); E5 0$y:
|79!exVMBp
UCHAR ncb_lana_num;
]=g|e
K*Tvo`
UCHAR ncb_cmd_cplt; (FAd'$lhX}
{1
94u%'
#ifdef _WIN64 x 1"ikp}
{G%!M+n<
UCHAR ncb_reserve[18]; ')w*c
Y">;2Pt;
#else l@om2|B
&p$SFH?s
UCHAR ncb_reserve[10]; &xqr&(o
B$ )6X
#endif s/K}]F
-ijQTB
HANDLE ncb_event; X+K$y:UZ
Tl3{)(ezx
} NCB, *PNCB; 0R2 AhA#
/-39od0
8EPV\M1%
ft[g1
重点在于ncb_command 成员。这个成员告诉Netbios该作什么。我们使用三个命令来探测MAC地址。他们在MSDN的定义如下: %?EOD=e=
*<! W k\
命令描述: =`X@+~%-
#={L!"3?e
NCBENUM Windows NT/2000: 列举系统中网卡的数量。使用此命令后,ncb_buffer成员指向由LANA_ENUM结构填充的缓冲区。 D4r5wc%
FBcF
NCBENUM 不是标准的 NetBIOS 3.0 命令。 y6o^ Knl
l%A~3
97Qng*i
Sn/~R|3XA7
NCBRESET 重置网卡。网卡在接受新的NCB命令之前必须重置。 TUEEwDK-
'.@R_sj
NCBASTAT 接受本地或远程接口卡的状态。使用此命令后,ncb_buffer成员指向由ADAPTER_STATUS结构填充的缓冲区,随后是NAME_BUFFER结构的数组。 j]<T\O>t>
0\jOg
t?]6>J_V
%Ys>PzM
下面就是取得您系统MAC地址的步骤: ]Nvtiw 6
0n,5"B
1》列举所有的接口卡。 ^>ca*g
%f&(U/
2》重置每块卡以取得它的正确信息。 morI'6N
|pp @
3》查询接口卡,取得MAC地址并生成标准的冒号分隔格式。 ?8(`tS(_?
S~F:%@,*
43-%")bH
~]/X,Cf
下面就是实例源程序。 |7/B20
#~.i\|VL
/)de`k"
7Yxy2[
#include <windows.h> 9,'5~+7
8'B\%.+"8e
#include <stdlib.h> \sC0om,
4T9hT~cT7
#include <stdio.h> %~ecrQ;
4W.;p"S2
#include <iostream> %`}CbD6
RQU5T 2,
#include <string> Z=!*7@QY
2>O2#53ls0
Xt=&
i&>,aiH@
using namespace std; J5Fg]O*
'{cN~A2b4
#define bzero(thing,sz) memset(thing,0,sz) z[v5hhI)4
>Fld7;L?<
Mn~A;=%qF
!nj%n
bool GetAdapterInfo(int adapter_num, string &mac_addr) \MtiLaI"
vEzzdDwi6
{ jD^L <
,0 &lag
// 重置网卡,以便我们可以查询 XU9=@y+|v
\Zf&&7v
NCB Ncb; hCT%1R}rKr
#4//2N
memset(&Ncb, 0, sizeof(Ncb));
Uzb"$Ue4
M:`hb$k:
Ncb.ncb_command = NCBRESET; Sc6wC H
X=\#n-*
Ncb.ncb_lana_num = adapter_num; yekIw
I I>2\d|
if (Netbios(&Ncb) != NRC_GOODRET) { \ @N> 38M
P>@`hZ9
o
mac_addr = "bad (NCBRESET): "; D?\K~U* >
2J4|7UwJ
mac_addr += string(Ncb.ncb_retcode); ;mi0Q.
1~ SY
return false; N@MeaO
N0vd>b
} HqXo;`Yy}
E;4Ns
z{#F9'\&
Y[~6f,?^
// 准备取得接口卡的状态块 zW0AB8l
&vMH
AZd
bzero(&Ncb,sizeof(Ncb); INbjk;k
m]-8?B1`Y
Ncb.ncb_command = NCBASTAT; %&_(IY$d
($S{td;
Ncb.ncb_lana_num = adapter_num; ^Nsl5
@5?T]V g
strcpy((char *) Ncb.ncb_callname, "*"); i9!Urq-
H;sQ]:.*]
struct ASTAT 4G>|It
=(n'#mV
{ zi?'3T%Ie
3yKI2en"
ADAPTER_STATUS adapt; J.<%E[
z
ax^${s|{-
NAME_BUFFER NameBuff[30]; 6ZG)`u".("
owMH
} Adapter; @6j*XF
.897Z|$VB
bzero(&Adapter,sizeof(Adapter)); >|Jw,,uf
4|$D.`Wu
Ncb.ncb_buffer = (unsigned char *)&Adapter; D} .t
3-mw-;.
Ncb.ncb_length = sizeof(Adapter); ,K9UT#h
`C*!de]Y%
<Y orQ>
44W3U~1
// 取得网卡的信息,并且如果网卡正常工作的话,返回标准的冒号分隔格式。 KFZ[gqW8YY
T?\CAk>
if (Netbios(&Ncb) == 0) Q"Ec7C5eM
y2 +a2
{ =O;SXzgE
@l(Y6m|v\
char acMAC[18]; jYy0^)6X(
_"sRL}-Z
sprintf(acMAC, "%02X:%02X:%02X:%02X:%02X:%02X", iO!lG
,{Ab=xV
int (Adapter.adapt.adapter_address[0]), ]~qN<x
6gKOpa
int (Adapter.adapt.adapter_address[1]), m_(hCY=Q$
i52R,hz
int (Adapter.adapt.adapter_address[2]),
yX-xVvlv@
s^oNQ}
int (Adapter.adapt.adapter_address[3]), ^z^>]Qd
r/4]b]n
int (Adapter.adapt.adapter_address[4]), P+b^;+\1s
Oq2H>eW`f
int (Adapter.adapt.adapter_address[5])); Iv<9})2K
*.*:(7`
mac_addr = acMAC; DO\EB6xH>%
!n{c#HfG
return true; UeICn@)\y
$1?X%8V
} 5{g9Wh[
JG<3,>@%
else %f-<ol
&!a2%%1#N
{ lBn*G&(P
m4DH90~a8
mac_addr = "bad (NCBASTAT): "; 5HbTgNI
Az-!LAu9 R
mac_addr += string(Ncb.ncb_retcode); 3EZw F
6J
5)4^bk
return false; [;=ky<K0E
cLU*Tx\
} Dy@\!F
yo.SPd="Vx
} ,>UmKrYo
*i{.@RX?
->hxHr`!%a
m6x. "jG
int main() `az`?`i7
cA%U
{ vs@:L)GW\
7:L~n(QpP
// 取得网卡列表 668bJ.M\O
U(N$6{i_
LANA_ENUM AdapterList; M([H\^\:
)/Xrhhx
NCB Ncb; \!QF9dP4
5lxq-E3
memset(&Ncb, 0, sizeof(NCB)); z{g<y^Im+E
I7PWOd
Ncb.ncb_command = NCBENUM; 9AYe,R
@c!67Z
Ncb.ncb_buffer = (unsigned char *)&AdapterList; L%d?eHF
12PE{Mut
Ncb.ncb_length = sizeof(AdapterList); v,+l xY
h<K;VpL6
Netbios(&Ncb); N ]7a=
zsXH{atY
'r n;|K
"|'`'W
// 取得本地以太网卡的地址 w)eQ'6Vu
)t0b$<%
string mac_addr; ptv4v[gQ
%9/)
for (int i = 0; i < AdapterList.length - 1; ++i) {@ y,
is?&%VY
{ _<a)\UR
I=%sDn
if (GetAdapterInfo(AdapterList.lana, mac_addr)) 4@e!D Du
>ij4z
N
{ /V<`L
t MZ(s
cout << "Adapter " << int (AdapterList.lana) << $l;tP
DiQkT R
"'s MAC is " << mac_addr << endl; b<(UmRxx3
%B&?D@
} I*t)x,~3
~9 WJrRWB
else ,Q#tA|:8j
/Z "
4[
{ /C"s_:m;3
D
Ok^ON
cerr << "Failed to get MAC address! Do you" << endl; aaugu.9
]A]E)*
cerr << "have the NetBIOS protocol installed?" << endl; 70
UgK E
RpK,ixbtA+
break; 7 3z
Y^x
*@arn Eu
} ~}0hN]*G
.&x?`pER
} -mHhB(Td'
z{3%Hq
/Tf*d>Yh;
0*;9CH=BE
return 0; :5K~/=6x
q&$0i
} CotMV^
y [9}[NMZ
A%*DQ1N
To8v#.i
第二种方法-使用COM GUID API }Q=se[((
M}oj!xGB
这种方法使用COM API创建一个GUID(全局唯一标识符)并从那里继承MAC地址。GUID通常用来标识COM组件以及系统中的其他对象。它们是由MAC地址(结合其他东西)计算得来的,表面上MAC地址就包含在其中。我说表面上是因为事实上并没有包含。 c^Gwri4
,q@(L
我提供这种方法更多的是为了作为反面教材。您也许用这种方法能够得到MAC地址,但有时候您只会得到随机的十六进制数值。 ms\/=96F
ar
qLp|
下面的例子十分简单,无需多讲。我们使用CoCreateGuid创建GUID,并将最后六个字节放入字符串中。它们可能是MAC地址,但并不是必然的。 #oroY.o
!bV(VRbu
i)= 89?8
7x7r!rSe,
#include <windows.h> gqdB!l4
KaQq[a
#include <iostream> DET!br'z5
Xf_tj:eO~
#include <conio.h> x\bR j>%(
Y5i`pY/}#?
G2+)R^FSC
D@(M+u9/%
using namespace std; v*'iWHCl,
ioY\8i
d! QD vO
BQuliX&
int main() zj$_iB`9
`^bvj]>l
{ [OoH5dD
;p#Z :6
cout << "MAC address is: "; Y\g90
rI^~9Rz
UGC|C F2K
N]s7/s
// 向COM要求一个UUID。如果机器中有以太网卡, n|mJE,N
>H1|c%w
// UUID最后的六个字节(Data4的2-7字节)应该是本地以太网卡的MAC地址。 .f !]@"\
^Q)gsJY|I
GUID uuid; -90ZI1O`
>uchF8)e|
CoCreateGuid(&uuid); QVG0>,+}$
;[OJ-|Q
// Spit the address out @maZlw1q
p[@oF5M
char mac_addr[18]; _KM $u>B8
O^R:_vb3I
sprintf(mac_addr,"%02X:%02X:%02X:%02X:%02X:%02X", gKs/T'PW
Q 9gFTLQ
uuid.Data4[2],uuid.Data4[3],uuid.Data4[4], Gx h~
Y0L5W;iM
uuid.Data4[5],uuid.Data4[6],uuid.Data4[7]); Z}K.^\S9
,+NE: _
cout << mac_addr << endl; ^Azt.\fMX
& GzhcW~
getch(); "\zj][sL
_Xk03\n6
return 0; L VU)W^
1IF'>*
} C DnR
\o62OfF!
FU(}=5n
zhA',p@K?_
"doU.U&u
o! 2n}C
第三种方法- 使用SNMP扩展API 3!"b
guE
0x]OF8=J
我要讨论的第三种方法是使用Windows的SNMP(简单网络管理协议)扩展来取得MAC地址。在我的经验里,这个协议很简单。代码也是直勾勾的向前的。基本步骤和Netbios相同: ~D-JZx
fNAo$O4cm
1》取得网卡列表 ]w_
y=oVUsG
2》查询每块卡的类型和MAC地址 /H%<oAjp6
e\^g|60f_
3》保存当前网卡 w]W`R.
PzMlua
我个人对SNMP了解不多,但如我刚刚所言,代码十分清楚。 u8<&F`7j
GTp?)nh^
^EC)~HP@C
co$Hi9JE
#include <snmp.h> z|G|Y 22
jHu,u|e0>S
#include <conio.h> ,#P,B;r~
#Cg}!38
#include <stdio.h> +#-kIaU
q:2aPfo&
*;OJ~zT
[xZ/ZWb/
typedef bool(WINAPI * pSnmpExtensionInit) ( C-a*EG
y~==waZw
IN DWORD dwTimeZeroReference, 2,8/Cb
55>" R{q
OUT HANDLE * hPollForTrapEvent, pB g|n=^
b"R, p=M
OUT AsnObjectIdentifier * supportedView); r
1l/) ;
!"`@sd~
e(OwS?K
D4=..;
typedef bool(WINAPI * pSnmpExtensionTrap) ( IdV,%d{
,YP1$gj
OUT AsnObjectIdentifier * enterprise, "<PoJPh
H )BOSZD
OUT AsnInteger * genericTrap, ),nCq^Bp
5"-una>D
OUT AsnInteger * specificTrap, }
*
?n?'
h*;g0QBkl
OUT AsnTimeticks * timeStamp, P3>..fhoW
%XEKhy
OUT RFC1157VarBindList * variableBindings); !G)mjvEe
/~o7Q$)-b
`y8
?=
8
3z'#
typedef bool(WINAPI * pSnmpExtensionQuery) ( :X'*8,]KHH
z+3<$Z
IN BYTE requestType, LJRg>8
ZNzR`6}
IN OUT RFC1157VarBindList * variableBindings,
_'!aj+{
1s{ISWm
OUT AsnInteger * errorStatus, u @{E{
pY+.SuM
OUT AsnInteger * errorIndex); 7ei>L]gm%
Q!4i_)rM
zY7*[!c2
(v|r'B9b
typedef bool(WINAPI * pSnmpExtensionInitEx) ( {l&Ltruhz
l^DINZU@
OUT AsnObjectIdentifier * supportedView); >.DF"]XM
+R|U4`12
k1ipvKxp:8
{Oy9RESqc
void main() =)(3Dp
;]2x
{ |ZvNH ~!
Uj4Lu
HINSTANCE m_hInst; u~$WH, P3
pyUNRqp
pSnmpExtensionInit m_Init; iBG`43;
1 L+=|*:
pSnmpExtensionInitEx m_InitEx; A)\>#Dv
;;ER"N
pSnmpExtensionQuery m_Query; "KMLk
YniZ(
~^K
pSnmpExtensionTrap m_Trap; `^v4zWDK
S304ncS|M
HANDLE PollForTrapEvent; Hze-Ob8
G 6Wx3~
AsnObjectIdentifier SupportedView; ( MB`hk-d
M
(+.$uz
UINT OID_ifEntryType[] = {1, 3, 6, 1, 2, 1, 2, 2, 1, 3}; `d75@0:
c5X`_
UINT OID_ifEntryNum[] = {1, 3, 6, 1, 2, 1, 2, 1}; q:vz?G
1*Sr5N[=
UINT OID_ipMACEntAddr[] = {1, 3, 6, 1, 2, 1, 2, 2, 1, 6}; .
_1jk
aRbx
AsnObjectIdentifier MIB_ifMACEntAddr = ykxbX
q^Z~IZ8IT
{ sizeof(OID_ipMACEntAddr) sizeof(UINT), OID_ipMACEntAddr }; 'Pf_5q
-G8c5b[
AsnObjectIdentifier MIB_ifEntryType = ~}h^38
~_'0]P\
{sizeof(OID_ifEntryType) sizeof(UINT), OID_ifEntryType}; q.-y)C) ;
_e6a8
AsnObjectIdentifier MIB_ifEntryNum = ?Q@L-H`
`'uUmyg
{sizeof(OID_ifEntryNum) sizeof(UINT), OID_ifEntryNum}; }ppVR$7]0
Ej'
7h~ =v
RFC1157VarBindList varBindList; *Wzwbwg
>4,{6<|
RFC1157VarBind varBind[2]; %PzQ\c
'nMApPl
AsnInteger errorStatus; :bwM]k*$
=g@R%NDNV
AsnInteger errorIndex; |Dg;(i?
{T&v2u#S
AsnObjectIdentifier MIB_NULL = {0, 0}; Y5HfN[u^7
$Z/klSEf
int ret; hF2/
y.:P
(Up'$J}
int dtmp; L{=l#vu
Ejq=*UOP
int i = 0, j = 0; lj)f4zu
8)sg_JC
bool found = false; 2A*/C7
t)ld<9)eB
char TempEthernet[13]; !(Q l)C
nB=0T`vQ
m_Init = NULL; Y[Es
~uB'3`x
m_InitEx = NULL; DR6]-j!FK
)%s +?
m_Query = NULL; B#]_8svO
tVunh3-
m_Trap = NULL; 1 o|T
Y&s2C%jT
s|Zx(.EP
fE^uF[-7?
/* 载入SNMP DLL并取得实例句柄 */ 6^sHgYR
e&2wdH&
m_hInst = LoadLibrary("inetmib1.dll"); @&5 A&(
4b4QbJ$
if (m_hInst < (HINSTANCE) HINSTANCE_ERROR) aM$\#Cx
eaQ90B4
{ f/ajejYo?,
AliRpxxd
m_hInst = NULL; ~n6[$WjZA
;-Ss# &
return; H>.B99vp
>dk9f}7-
} ('t kZt%8
>!}`%pk(
m_Init = QsOhz
-l
"U"U"F
(pSnmpExtensionInit) GetProcAddress(m_hInst, "SnmpExtensionInit"); t^.'>RwW|
)Pli})
m_InitEx = M-Y0xWs
&8sV
o@Pa
(pSnmpExtensionInitEx) GetProcAddress(m_hInst, 5 [4Z=RP
XrS\+y3
"SnmpExtensionInitEx"); L,~MicgV
o 7G> y#Y
m_Query = f jI #-
Wr>(#*r7q
(pSnmpExtensionQuery) GetProcAddress(m_hInst, pCC 7(Ouo
9=
V>f)R
"SnmpExtensionQuery"); dv7<AJ
aX^+ O,
m_Trap = Pdw#o^Iq^
4<.O+hS
(pSnmpExtensionTrap) GetProcAddress(m_hInst, "SnmpExtensionTrap"); r~8;kcu7
DZe}y^F
m_Init(GetTickCount(), &PollForTrapEvent, &SupportedView); 5lTD]d
.^[_V
.$Bwb/a
%9o+zg? RJ
/* 初始化用来接收m_Query查询结果的变量列表 */ M^6$
MMx
W&(f&{A
varBindList.list = varBind; Ax!Gu$K2o
kZVm1W1
varBind[0].name = MIB_NULL; z/1{OL
xMI+5b8
varBind[1].name = MIB_NULL; 0Q~@F3N-\>
O"*`'D|hK
ni6r{eSQ
2yKz-"E
/* 在OID中拷贝并查找接口表中的入口数量 */ $%PVJs
&[@\ f^~
varBindList.len = 1; /* Only retrieving one item */ :.iyR
S &JJIFftO
SNMP_oidcpy(&varBind[0].name, &MIB_ifEntryNum); 5+P@sD
gLQ #4H
ret = ^7aN2o3{
>fzwFNdo
m_Query(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus, \iU] s\{).
Y)XvlfJ,h?
&errorIndex); >t3'_cBC!
g:<?
printf("# of adapters in this system : %in", M=y0PCD
n.hElgkUOr
varBind[0].value.asnValue.number); 59*M"1['Q
KrKu7]If6#
varBindList.len = 2; ;;V\"7q'
!QEL"iJ6M'
U,;xZe
B9X8
/* 拷贝OID的ifType-接口类型 */ 7>i2OBkAhB
k\N4@UK
SNMP_oidcpy(&varBind[0].name, &MIB_ifEntryType); w#(RW7":F
8LJ{i%
!@g)10u
1f4bt6[
/* 拷贝OID的ifPhysAddress-物理地址 */ ;/LD)$_
u+D[_yd^
SNMP_oidcpy(&varBind[1].name, &MIB_ifMACEntAddr); x*}bo))hb
4;KWG}~[o
0JY WrPR
[VSU"AJY
do EO)%UrWnC
+.Bmkim
{ iOqk*EL_r\
7Kf}O6nE
V U~Dk);Bv
#Hu~}zy
/* 提交查询,结果将载入 varBindList。 Ip?]K*sq
G'x .NL
可以预料这个循环调用的次数和系统中的接口卡数量相等 */ E\{< ;S
vR>o}%`
ret = z`$J_Cj Y
wJG$c-(\0
m_Query(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus, C!%:o/
;sPzOS9
&errorIndex); #[ -\lU|
K: r\{#9
if (!ret) *t9eZ!_f?
[!"XcFY:a
ret = 1; %<Q*Jf
27 GhE
else 'Qn~H[$/p
KhaYr)&~
/* 确认正确的返回类型 */ o-eKAkh
^_>!B)
ret = SNMP_oidncmp(&varBind[0].name, &MIB_ifEntryType, Q\kub_I{@
Sm|(
MIB_ifEntryType.idLength); m)&znLA
SEF6B45}1
if (!ret) { \#dl6:"
=P^wh
j++; +S~.c;EK
{G*QY%j^
dtmp = varBind[0].value.asnValue.number; GsV4ZZ
M{N(~ql
printf("Interface #%i type : %in", j, dtmp); 6Nh0
d^V$Z6*
]
E9 Y\X
HJhH-\{@
/* Type 6 describes ethernet interfaces */ S>_27r{
;-@=
if (dtmp == 6) }zMf7<C
B|o%_:]+E
{ >a>fb|r
R+=a`0_S
#y; yN7W
BWUq%o,@g
/* 确认我们已经在此取得地址 */ G '#41>q+
vR hnX
ret = Hs?zq
F^kwdS
SNMP_oidncmp(&varBind[1].name, &MIB_ifMACEntAddr, 8 i0
hW2.8f$
MIB_ifMACEntAddr.idLength); &M"ouy Zo9
wH6u5*$p
if ((!ret) && (varBind[1].value.asnValue.address.stream != NULL)) ]=&L