sms信息

短信

短信概述

SMS(Short Messaging Service)

sms

SMS协议就是短信协议的一种,目前短信协议有SMS短信、EMS短信和MMS彩信。

SMS,短信服务是最早的短消息业务,也是现在普及率最高的一种短消息业务,通过它移动电话之间可以互相收发短信,内容以文本、数字或二进制非文本数据为主,目前,这种短消息的长度被限定在140字节之内。SMS以简单方便的使用功能受到广大用户的欢迎,迅速普及,但却始终是属于第一代的无线数据服务。

SMS 是一种存储和转发服务。也就是说,短消息并不是直接从发送人发送到接收人,而始终通过 SMS 中心进行转发。如果接收人处于未连接状态(可能电话已关闭),则消息将在接收人再次连接时发送。

PDU编码

共有三种方式来发送和接收SMS信息:Block Mode, Text Mode和PDU Mode。其中PDU Mode被所有手机支持,可以使用任何字符集,这也是手机默认的编码方式。

PDU相当于一个数据包、数据单元,它由构成短消息(SMS)的信息组成。

GSM和CDMA的PDU又有着很大的区别。


GSM短信编码

短信包含很多的类型,如短信交付(SMS-DELIVER)、短信提交(SMS -SUBMIT)、短信命令(SMS-DELIVER)等。这里主要讲短信交付。

SMS-DELIVER (Mobile Terminated):手机接受的短信,由短信中心到终端。 SMS-SUBMIT (Mobile Originated):由手机发起的短信,由终端到短信中心。

短信交付流程

PDU的组成

PDU主要由以下部分组成:

pdu

例如:

240D91688102200982F6010821800381602423064F60597D0021

240D91688102200982F60104218003816024230b68656c6c6f20776f726c64

240D91688102200982F60100218003816024230bc8329bfd065ddf72363904

字段含义如下表

元素 名称 长度 描述
SCA Service Center Address 1-12 短消息服务中心号码
PDU-Type Protocol Data Unit 1 协议数据单元类型
MR Message Reference 1 所有成功的短信发送参考数目(0..255)
OA Originator Address 2-12 发送方地址(手机号码)
PID Protocol Identifer 1 参数显示消息中心以何种方式处理消息内容
DCS Data Coding Scheme 1 参数显示用户数据编码方案
SCTS Service Center Time Stamp 7 消息中心收到消息时的时间戳
UDL User Data Lenghth 1 用户数据长度
UD User Data 1 用户数据

短信信息的解码主要关注红色的元素

GSM短信解析流程

GSM短信解析流程

PDU-Type

PDU-Type包含了MTI具体信息如下:

PDU-Type

其中2bit MTI如下:

MTI

OA

OA 发送方地址(Originator Address)例如:0D 91 688102200982F6

1 Octet 0-1 Octet 0-10 Octet
Len Type Addr
  • Len:地址长度。如果Length为0D,后面的字节数是[2+(Length+1)]/2=8,后面8个字节是发送方的地址;
  • Type:短消息中心地址的类型,一般为91,代表“+”。
  • Addr:地址长度为奇数时,最后一个需要填充”F”

DCS

DCS

2-3bit代表用户数据的编码方式,0-1bit代表了短信的储存方式

  • Class0:短消息直接显示到用户终端
  • Class1:短消息存储在SIM卡上
  • Class2:短消息必须存储在SIM卡上,禁止直接传输到中断
  • Class3:短消息存贮在用户设备上

SCTS

1bit-7bit分别代表年 月 日 时 分 秒 时区

例如:

21 80 03 81 60 24 23代表12年8月30号18时6分24秒

UDL

UDL用户数据长度,包含用户数据和用户数据头的长度

  1. 如果用户用默认7位编码。表示的是编码前的字符串长度,而不是编码后的8位组个数!

  2. 如果用户用8位编码表示用户数据区的字节数,有数据头信息,包括在内。

  3. 如果为UCS2编码,则是用户数据区的字节数

UD

用户数据

例如:
1、04 4F60597D(不包含用户头部信息)

用户数据长度:4

用户数据:4F60597D

2、08 050003000201 C834 (包含用户头部信息)

用户数据长度:8

用户数据:C834

用户头部长度:5

用户头部信息:0003000201

UDH

050003000201

  • 05表示消息头后续长度
  • 00表示消息类型为长短信拆分
  • 03表示剩余短信消息头标识长度
  • 00表示短信ID,范围0~255
  • 02表示短信拆分总包数
  • 01表示当前短信是拆分短信的第几条

CDMA短信编码

CDMA PDU

pdu如下:

00 00 02 10 02 02 07 02 c5 4c e2 25 a8 a8 06 01 4c 08 4d 00 03 10 01 f8 01 3e 20 f0 01 90 01 78 01 90 01 62 df ca 70 04 b1 ac b1 ab b4 23 96 14 c6 70 01 62 96 3b 2b 12 b9 82 7a e3 10 c0 01 72 9f 54 4c 0b 10 8b b4 23 91 8a 75 d0 01 63 31 7a 70 02 9f 52 e0 7c f0 f8 03 06 08 12 29 19 26 16

CDMA PDU总体分为两部分:消息类型 + 字段

  • 0x00:点对点消息
  • 0x00:字段类型
  • 0x02:字段长度

字段类型分为:0x00:Teleservice id;0x02:Originating addr;0x06:Bearer reply opt;0x08:Bearer data

CDMA短信解析流程

CDMA短信解析流程

Originating addr

02 07 02 c5 4c e2 25 a8 a8

  • 0x02:addr
  • 0x07:长度
  • 0x02,0xc5:0000 0010 1100 0101
  • 第一个bit表示地址编码方式:
  • 0 : 4bit压缩;
  • 1 : 8bit压缩
  • 第二个bit表示NUMBER_MODE
  • 0:RIL_CDMA_SMS_NUMBER_MODE_NOT_DATA_NETWORK
  • 接着8bit表示号码长度
  • 0000 1011:11位号码

Bearer data

08 4d 00 03 10 01 f8 01 3e 20 f0 01 90 01 78 01 90 01 62 df ca 70 04 b1 ac b1 ab b4 23 96 14 c6 70 01 62 96 3b 2b 12 b9 82 7a e3 10 c0 01 72 9f 54 4c 0b 10 8b b4 23 91 8a 75 d0 01 63 31 7a 70 02 9f 52 e0 7c f0 f8 03 06 08 12 29 19 26 16

  • 0x08:data
  • 0x4d:长度77

Data的内容也是由字段组成:

Data

IDENTIFER

00 03 10 01 f8

  • 0x03:长度
  • 0xf8:最后一个8bit中的第5个bit代表header_ind

USR DATA

01 3e 20 f0 01 90 01 78 01 90 01 62 df ca 70 04 b1 ac b1 ab b4 23 96 14 c6 70 01 62 96 3b 2b 12 b9 82 7a e3 10 c0 01 72 9f 54 4c 0b 10 8b b4 23 91 8a 75 d0 01 63 31 7a 70 02 9f 52 e0 7c f0

0x3e:长度

20 f0 01: 0010 0000 1111 0000 0000 0001

  • 前5个bit表示编码方式: 7bit(0x02) 、8bit (其他)、UCS2(0x04)
  • 接着8个bit表示字符长度,剩余部分为数据

TIME_STAMP

03 06 08 12 29 19 26 16

  • 0x06:长度
  • 08 12 29 19 26 16:08年12月29号19时26分16秒

短信解码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
#include <stdio.h>
#include <string.h>
#include <iconv.h>
#include <errno.h>

#define HIGH_8BIT_MASK(N) (0xFF << (N))
#define LOW_8BIT_MASK(N) (~HIGH_8BIT_MASK(N))

void gsmpdu_decode(const char *pdu);
int ascii_to_hex(const char *ascii, int ascii_length, char *hex, int *hex_length);
int hex_to_ascii(const char *hex, int hex_length, char *ascii, int *ascii_length);
int dencode_ucs2(char *in, int in_length, char *out, int *out_length);
int get_time(char *pdu, int length, char *timer);
int get_number(char *pdu_hex, int number_length, char *number);
int decode_8bit(char *in, int in_length, char *out, int *out_length);
int _7bit_to_ascii(char *p_dst, unsigned char *p_src, int src_size);

void gsmpdu_decode(const char *pdu)
{
int offset = 0;
int pdu_length = 0;
int number_length = 0;
int pdu_hex_length = 0;
int pdu_type = 0;
int code_mode = 0;
int pdu_udl = 0;
int pdu_udhl = 0;
char number[64];
char timer[64];
char usrdata[640] = {0};
int datalength = 0;

pdu_length = strlen(pdu);
char m_pdu[pdu_length + 1];
strncpy(m_pdu, pdu, pdu_length);

pdu_hex_length = pdu_length / 2 + 1;
char pdu_hex[pdu_hex_length];
ascii_to_hex(pdu, pdu_length, pdu_hex, &pdu_hex_length);

pdu_type = pdu_hex[offset++];
if (pdu_type & 0x02)
{
printf("status!\n no this faction!\n");
return;
}
else
{
printf("message!\n");
}

number_length = pdu_hex[offset++] & 0xff;
if (number_length & 0x01)
number_length++;
else
{
printf("number_length!\n");
}

number_length = number_length / 2 + 1;
int num = get_number(pdu_hex + offset, number_length, number);
printf("Call Number : %s\tNumber Length :%d\n", number, num);
offset += number_length;
offset++; /*PID*/

code_mode = pdu_hex[offset++] & 0xff; /*dcs*/

get_time(pdu_hex + offset, 7, timer);
printf("Send Time : %s\n", timer);
offset += 7;

pdu_udl = pdu_hex[offset++] & 0xff; /*udl*/
printf("%d\n", pdu_udl);

if (pdu_type & 0x40)
{
pdu_udhl = pdu_hex[offset] & 0xff;
printf("do not decode UDH");
offset += pdu_udhl;
}

if (code_mode & 0x08)
{
dencode_ucs2(pdu_hex + offset, pdu_udl, usrdata, &datalength);
//ucs-2
printf("%s\n", usrdata);
}
else if (code_mode & 0x04)
{
decode_8bit(pdu_hex + offset + pdu_udhl, pdu_udl - pdu_udhl, usrdata, &datalength);
//8-bit
printf("%s\n", usrdata);
}
else
{
_7bit_to_ascii(usrdata, (unsigned char *)(pdu_hex + offset), pdu_udl);
printf("%s\n", usrdata);
}

return;
}

int ascii_to_hex(const char *ascii, int ascii_length, char *hex, int *hex_length)
{
int length = 0;
int index = 0;
if (ascii == NULL || hex == NULL || hex_length == NULL || ascii_length <= 0)
{
return -1;
}

for (; index < ascii_length; index++)
{
if (index % 2 == 0)
{
hex[index / 2] = 0x00;
length++;
}
else
{
hex[index / 2] = hex[index / 2] << 4;
}

if (ascii[index] >= '0' && ascii[index] <= '9')
{
hex[index / 2] |= ascii[index] - '0';
}
else if (ascii[index] >= 'a' && ascii[index] <= 'f')
{
hex[index / 2] |= ascii[index] - 'a' + 10;
}
else if (ascii[index] >= 'A' && ascii[index] <= 'F')
{
hex[index / 2] |= ascii[index] - 'A' + 10;
}
else
{
break;
}
}

*hex_length = length;

return 0;
}

int hex_to_ascii(const char *hex, int hex_length, char *ascii, int *ascii_length)
{
char temp = 0x00;
int length = 0;
int index = 0;

if (hex == NULL || hex_length <= 0 || ascii == NULL || ascii_length == NULL)
{
return -1;
}

for (; index < hex_length; index++)
{
temp = (hex[index] >> 4) & 0x0F;

if (temp >= 0x00 && temp <= 0x09)
{
ascii[length] = temp + '0';
}
else if (temp >= 0x0A && temp <= 0x0F)
{
ascii[length] = temp - 0x0A + 'A';
}
length++;

temp = hex[index] & 0x0F;
if (temp >= 0x00 && temp <= 0x09)
{
ascii[length] = temp + '0';
}
else if (temp >= 0x0A && temp <= 0x0F)
{
ascii[length] = temp - 0x0A + 'A';
}
length++;
}

*ascii_length = length;

return 0;
}

int decode_8bit(char *in, int in_length, char *out, int *out_length)
{
int length = 0;

if (in == NULL || in_length <= 0 || out == NULL || out_length == NULL)
{
return -1;
}

for (int index = 0; index < in_length; index++)
{
out[length++] = in[index];
}
*out_length = length;

return 0;
}

int dencode_ucs2(char *in, int in_length1, char *out, int *out_length)
{
iconv_t icon_handler = 0;
int in_length = 0;
char *inbuff;
int out_buffer_length;
char *out_buffer;
char temp = 0x00;
in_length = in_length1;
out_buffer_length = *out_length;

if (in == NULL || in_length <= 0 || in_length % 2 != 0 || out == NULL || out_length == NULL)
{
return -1;
}

for (int index = 0; index < in_length; index += 2)
{
temp = in[index];
in[index] = in[index + 1];
in[index + 1] = temp;
}

if ((icon_handler = iconv_open("utf-8", "ucs-2")) == 0)
{
return -1;
}

out_buffer = out;
inbuff = in;
if (iconv(icon_handler, &inbuff, (size_t *)&in_length, &out_buffer, (size_t *)&out_buffer_length) == -1)
{
printf("decode_ucs2 errno = %d.\n", errno);
iconv_close(icon_handler);
return -1;
}
iconv_close(icon_handler);

return 0;
}

int _7bit_to_ascii(char *p_dst, unsigned char *p_src, int src_size)
{
int i = 0;
int n = 0;
int pos = 0;
int left = 0;
char high_part, low_part;
left = 8;

n = (src_size * 8) / 7;
for (i = 0; i < n; i++)
{
if (left == 8)
{

p_dst[i] = p_src[pos] & LOW_8BIT_MASK(7);
left -= 7;
}
else if (left == 7)
{
p_dst[i] = (p_src[pos] & HIGH_8BIT_MASK(8 - left)) >> (8 - left);
left = 8;
pos++;
}
else
{
low_part = high_part = 0;
low_part = (p_src[pos] & HIGH_8BIT_MASK(8 - left)) >> (8 - left);
high_part = (p_src[pos + 1] & LOW_8BIT_MASK(7 - left)) << left;
p_dst[i] = high_part | low_part;
left = 8 - (7 - left);
pos++;
}
}
return n;
}

int get_number(char *pdu_hex, int number_length, char *number)
{
int offset = 0;
int num_length = 0;
int index = 0;
int i = 0;

int type = pdu_hex[offset++] & 0xff;
if (type == 145)
{
number[index++] = '+';
}
else
{
printf("error!\n");
}

for (; i < number_length; i++)
{
pdu_hex[offset + i] = ((pdu_hex[offset + i] >> 4) & 0x0f) | ((pdu_hex[offset + i] << 4) & 0xf0);
}

hex_to_ascii(pdu_hex + offset, number_length - 1, number + index, &num_length);
if (number[num_length + index - 1] == 'f' || number[num_length + index - 1] == 'F')
{
number[num_length + index - 1] = 0x00;
num_length--;
}
return num_length;
}

int get_time(char *pdu, int length, char *timer)
{
/*int offset = 0;
int timer_length = 0;
int i = 0;

for(;i<length;i++)
{
pdu_hex[offset+i] = ((pdu_hex[offset+i]>>4)&0x0f)|((pdu_hex[offset+i]<<4)&0xf0);
}

return hex_to_ascii(pdu_hex+offset, length-1, timer, &timer_length);*/

int year = 2000;
int mouth = 0;
int day = 0;
int hour = 0;
int minute = 0;
int second = 0;
int zone = 0;

year += ((pdu[0] >> 4) & 0x0F) + (pdu[0] & 0x0F) * 10;
mouth += ((pdu[1] >> 4) & 0x0F) + (pdu[1] & 0x0F) * 10;
day += ((pdu[2] >> 4) & 0x0F) + (pdu[2] & 0x0F) * 10;
hour += ((pdu[3] >> 4) & 0x0F) + (pdu[3] & 0x0F) * 10;
minute += ((pdu[4] >> 4) & 0x0F) + (pdu[4] & 0x0F) * 10;
second += ((pdu[5] >> 4) & 0x0F) + (pdu[5] & 0x0F) * 10;
zone += ((pdu[6] >> 4) & 0x0F) + (pdu[6] & 0x0F) * 10;

sprintf(timer, "%04d-%02d-%02d %02d:%02d:%02d", year, mouth, day, hour, minute, second);

return 0;
}

int main()
{
/*DCS:08*/
char *p = "240D91687113988853F90000126080916090230F31D98C56B3FD403FD00FF403";
char *q = "240D91688102200982F60104218003816024230b68656c6c6f20776f726c64";
char *b = "240D91688102200982F60100218003816024230bc8329bfd065ddf72363904";
char *test = "240D91688102200982F601002180038160242304D4F29C0E";
gsmpdu_decode(p);
gsmpdu_decode(q);
gsmpdu_decode(b);
gsmpdu_decode(test);
return 0;
}

sms信息
https://carl-5535.github.io/2021/07/17/工作总结/sms信息/
作者
Carl Chen
发布于
2021年7月17日
许可协议